diff --git a/lib/client.go b/lib/client.go index 12f9cc4b7..6fe00d597 100644 --- a/lib/client.go +++ b/lib/client.go @@ -340,7 +340,7 @@ func (c *Client) handleIdemixEnroll(req *api.EnrollmentRequest) (*EnrollmentResp return nil, errors.WithMessage(err, fmt.Sprintf("Failed to decode issuer public key that was returned by CA %s", req.CAName)) } // Create credential request - credReq, sk, rand, err := c.newIdemixCredentialRequest(nonce, ipkBytes) + credReq, sk, err := c.newIdemixCredentialRequest(nonce, ipkBytes) if err != nil { return nil, errors.WithMessage(err, "Failed to create an Idemix credential request") } @@ -367,7 +367,7 @@ func (c *Client) handleIdemixEnroll(req *api.EnrollmentRequest) (*EnrollmentResp return nil, err } log.Infof("Successfully received Idemix credential from CA %s", req.CAName) - return c.newIdemixEnrollmentResponse(identity, &result, sk, rand, req.Name) + return c.newIdemixEnrollmentResponse(identity, &result, sk, req.Name) } // addAuthHeaderForIdemixEnroll adds authenticate header to the specified HTTP request @@ -430,30 +430,18 @@ func (c *Client) newEnrollmentResponse(result *common.EnrollmentResponseNet, id // newIdemixEnrollmentResponse creates a client idemix enrollment response from a network response func (c *Client) newIdemixEnrollmentResponse(identity *Identity, result *common.IdemixEnrollmentResponseNet, - sk, rand *fp256bn.BIG, id string) (*EnrollmentResponse, error) { + sk *fp256bn.BIG, id string) (*EnrollmentResponse, error) { log.Debugf("newIdemixEnrollmentResponse %s", id) credBytes, err := util.B64Decode(result.Credential) if err != nil { return nil, errors.WithMessage(err, "Invalid response format from server") } - icred := &idemix.Credential{} - err = proto.Unmarshal(credBytes, icred) - if err != nil { - return nil, errors.WithMessage(err, "Failed to unmarshal Idemix credential bytes") - } - - icred.Complete(rand) - ccredBytes, err := proto.Marshal(icred) - if err != nil { - return nil, errors.WithMessage(err, "Failed to marshal completed Idemix credential") - } - // Create SignerConfig object with credential bytes from the response // and secret key isAdmin, _ := strconv.ParseBool(result.Attrs["Role"]) signerConfig := &idemixcred.SignerConfig{ - Cred: ccredBytes, + Cred: credBytes, Sk: idemix.BigToBytes(sk), IsAdmin: isAdmin, OrganizationalUnitIdentifier: result.Attrs["OU"], @@ -512,19 +500,18 @@ func (c *Client) newCertificateRequest(req *api.CSRInfo) *csr.CertificateRequest // newIdemixCredentialRequest returns CredentialRequest object, a secret key, and a random number used in // the creation of credential request. -func (c *Client) newIdemixCredentialRequest(nonce *fp256bn.BIG, ipkBytes []byte) (*idemix.CredRequest, *fp256bn.BIG, *fp256bn.BIG, error) { +func (c *Client) newIdemixCredentialRequest(nonce *fp256bn.BIG, ipkBytes []byte) (*idemix.CredRequest, *fp256bn.BIG, error) { rng, err := idemix.GetRand() if err != nil { - return nil, nil, nil, err + return nil, nil, err } sk := idemix.RandModOrder(rng) - randCred := idemix.RandModOrder(rng) issuerPubKey, err := c.getIssuerPubKey(ipkBytes) if err != nil { - return nil, nil, nil, err + return nil, nil, err } - return idemix.NewCredRequest(sk, randCred, nonce, issuerPubKey, rng), sk, randCred, nil + return idemix.NewCredRequest(sk, nonce, issuerPubKey, rng), sk, nil } func (c *Client) getIssuerPubKey(ipkBytes []byte) (*idemix.IssuerPublicKey, error) { diff --git a/lib/server/idemix/enroll_test.go b/lib/server/idemix/enroll_test.go index 040b7fdc7..69a50cd98 100644 --- a/lib/server/idemix/enroll_test.go +++ b/lib/server/idemix/enroll_test.go @@ -159,7 +159,7 @@ func TestHandleIdemixEnrollForCredentialError(t *testing.T) { handler := EnrollRequestHandler{Ctx: ctx, IdmxLib: idemixlib, Issuer: issuer} nonce := handler.GenerateNonce() - credReq, _, _, err := newIdemixCredentialRequest(t, nonce) + credReq, _, err := newIdemixCredentialRequest(t, nonce) if err != nil { t.Fatalf("Failed to create credential request: %s", err.Error()) } @@ -224,7 +224,7 @@ func TestHandleIdemixEnrollCheckNonceError(t *testing.T) { caller := new(mocks.User) caller.On("Name").Return("foo") - credReq, _, _, err := newIdemixCredentialRequest(t, nonce) + credReq, _, err := newIdemixCredentialRequest(t, nonce) if err != nil { t.Fatalf("Failed to create test credential request") } @@ -283,7 +283,7 @@ func TestHandleIdemixEnrollNewCredError(t *testing.T) { caller.On("GetAttribute", "isAdmin").Return(&api.Attribute{Name: "isAdmin", Value: "true"}, nil) caller.On("LoginComplete").Return(nil) - credReq, _, _, err := newIdemixCredentialRequest(t, nonce) + credReq, _, err := newIdemixCredentialRequest(t, nonce) if err != nil { t.Fatalf("Failed to create test credential request") } @@ -347,7 +347,7 @@ func TestHandleIdemixEnrollInsertCredError(t *testing.T) { caller.On("GetAttribute", "isAdmin").Return(&api.Attribute{Name: "isAdmin", Value: "true"}, nil) caller.On("LoginComplete").Return(nil) - credReq, _, _, err := newIdemixCredentialRequest(t, nonce) + credReq, _, err := newIdemixCredentialRequest(t, nonce) if err != nil { t.Fatalf("Failed to create test credential request") } @@ -425,7 +425,7 @@ func TestHandleIdemixEnrollForCredentialSuccess(t *testing.T) { caller.On("GetAttribute", "isAdmin").Return(&api.Attribute{Name: "isAdmin", Value: "true"}, nil) caller.On("LoginComplete").Return(nil) - credReq, _, _, err := newIdemixCredentialRequest(t, nonce) + credReq, _, err := newIdemixCredentialRequest(t, nonce) if err != nil { t.Fatalf("Failed to create test credential request") } @@ -503,7 +503,7 @@ func getReadBodyFunc(t *testing.T, credReq *idemix.CredRequest) func(body interf } } -func newIdemixCredentialRequest(t *testing.T, nonce *amcl.BIG) (*idemix.CredRequest, *amcl.BIG, *amcl.BIG, error) { +func newIdemixCredentialRequest(t *testing.T, nonce *amcl.BIG) (*idemix.CredRequest, *amcl.BIG, error) { idmxlib := new(mocks.Lib) issuerCred := NewIssuerCredential(testPublicKeyFile, testSecretKeyFile, idmxlib) err := issuerCred.Load() @@ -516,9 +516,8 @@ func newIdemixCredentialRequest(t *testing.T, nonce *amcl.BIG) (*idemix.CredRequ } rng, err := idemix.GetRand() if err != nil { - return nil, nil, nil, err + return nil, nil, err } sk := idemix.RandModOrder(rng) - randCred := idemix.RandModOrder(rng) - return idemix.NewCredRequest(sk, randCred, nonce, ik.IPk, rng), sk, randCred, nil + return idemix.NewCredRequest(sk, nonce, ik.IPk, rng), sk, nil } diff --git a/vendor/github.com/hyperledger/fabric/idemix/credential.go b/vendor/github.com/hyperledger/fabric/idemix/credential.go index 8ba62e33d..5adc5a5c1 100644 --- a/vendor/github.com/hyperledger/fabric/idemix/credential.go +++ b/vendor/github.com/hyperledger/fabric/idemix/credential.go @@ -81,11 +81,6 @@ func NewCredential(key *IssuerKey, m *CredRequest, attrs []*FP256BN.BIG, rng *am CredAttrs}, nil } -// Complete completes the credential by updating it with the randomness used to generate CredRequest -func (cred *Credential) Complete(credS1 *FP256BN.BIG) { - cred.S = BigToBytes(Modadd(FP256BN.FromBytes(cred.S), credS1, GroupOrder)) -} - // Ver cryptographically verifies the credential by verifying the signature // on the attribute values and user's secret key func (cred *Credential) Ver(sk *FP256BN.BIG, ipk *IssuerPublicKey) error { diff --git a/vendor/github.com/hyperledger/fabric/idemix/credrequest.go b/vendor/github.com/hyperledger/fabric/idemix/credrequest.go index 638e739ca..c8959eabd 100644 --- a/vendor/github.com/hyperledger/fabric/idemix/credrequest.go +++ b/vendor/github.com/hyperledger/fabric/idemix/credrequest.go @@ -31,15 +31,13 @@ const credRequestLabel = "credRequest" // the signature value, a randomness used to create the signature, the user secret, and the attribute values // NewCredRequest creates a new Credential Request, the first message of the interactive credential issuance protocol (from user to issuer) -func NewCredRequest(sk *FP256BN.BIG, credS1 *FP256BN.BIG, IssuerNonce *FP256BN.BIG, ipk *IssuerPublicKey, rng *amcl.RAND) *CredRequest { +func NewCredRequest(sk *FP256BN.BIG, IssuerNonce *FP256BN.BIG, ipk *IssuerPublicKey, rng *amcl.RAND) *CredRequest { HSk := EcpFromProto(ipk.HSk) - HRand := EcpFromProto(ipk.HRand) - Nym := HSk.Mul2(sk, HRand, credS1) + Nym := HSk.Mul(sk) // Create ZK Proof rSk := RandModOrder(rng) - rRand := RandModOrder(rng) - t := HSk.Mul2(rSk, HRand, rRand) + t := HSk.Mul(rSk) // proofData is the data being hashed, it consists of: // the credential request label @@ -56,10 +54,9 @@ func NewCredRequest(sk *FP256BN.BIG, credS1 *FP256BN.BIG, IssuerNonce *FP256BN.B copy(proofData[index:], ipk.Hash) proofC := HashModOrder(proofData) - proofS1 := Modadd(FP256BN.Modmul(proofC, sk, GroupOrder), rSk, GroupOrder) - proofS2 := Modadd(FP256BN.Modmul(proofC, credS1, GroupOrder), rRand, GroupOrder) + proofS := Modadd(FP256BN.Modmul(proofC, sk, GroupOrder), rSk, GroupOrder) - return &CredRequest{EcpToProto(Nym), BigToBytes(IssuerNonce), BigToBytes(proofC), BigToBytes(proofS1), BigToBytes(proofS2)} + return &CredRequest{EcpToProto(Nym), BigToBytes(IssuerNonce), BigToBytes(proofC), BigToBytes(proofS), nil} } // Check cryptographically verifies the credential request @@ -67,17 +64,15 @@ func (m *CredRequest) Check(ipk *IssuerPublicKey) error { Nym := EcpFromProto(m.GetNym()) IssuerNonce := FP256BN.FromBytes(m.GetIssuerNonce()) ProofC := FP256BN.FromBytes(m.GetProofC()) - ProofS1 := FP256BN.FromBytes(m.GetProofS1()) - ProofS2 := FP256BN.FromBytes(m.GetProofS2()) + ProofS := FP256BN.FromBytes(m.GetProofS1()) HSk := EcpFromProto(ipk.HSk) - HRand := EcpFromProto(ipk.HRand) - if Nym == nil || IssuerNonce == nil || ProofC == nil || ProofS1 == nil || ProofS2 == nil { + if Nym == nil || IssuerNonce == nil || ProofC == nil || ProofS == nil { return errors.Errorf("one of the proof values is undefined") } - t := HSk.Mul2(ProofS1, HRand, ProofS2) + t := HSk.Mul(ProofS) t.Sub(Nym.Mul(ProofC)) // proofData is the data being hashed, it consists of: diff --git a/vendor/github.com/hyperledger/fabric/idemix/idemix.pb.go b/vendor/github.com/hyperledger/fabric/idemix/idemix.pb.go index 68d014851..b770e2136 100644 --- a/vendor/github.com/hyperledger/fabric/idemix/idemix.pb.go +++ b/vendor/github.com/hyperledger/fabric/idemix/idemix.pb.go @@ -15,7 +15,12 @@ It has these top-level messages: Credential CredRequest Signature + NonRevokedProof + PlainSigNonRevokedProof NymSignature + CredentialRevocationInformation + PlainSigRevocationData + MessageSignature */ package idemix @@ -331,23 +336,27 @@ func (m *CredRequest) GetProofS2() []byte { // and a zero-knowledge proof of knowledge of a credential // and the corresponding user secret together with the attribute values // Nonce - a fresh nonce used for the signature -// Nym - a fresh pseudonym (a commitment to to the user secert) +// Nym - a fresh pseudonym (a commitment to to the user secret) // ProofSRNym - a zero-knowledge proof of knowledge of the // user secret inside Nym type Signature struct { - APrime *ECP `protobuf:"bytes,1,opt,name=APrime" json:"APrime,omitempty"` - ABar *ECP `protobuf:"bytes,2,opt,name=ABar" json:"ABar,omitempty"` - BPrime *ECP `protobuf:"bytes,3,opt,name=BPrime" json:"BPrime,omitempty"` - ProofC []byte `protobuf:"bytes,4,opt,name=ProofC,proto3" json:"ProofC,omitempty"` - ProofSSk []byte `protobuf:"bytes,5,opt,name=ProofSSk,proto3" json:"ProofSSk,omitempty"` - ProofSE []byte `protobuf:"bytes,6,opt,name=ProofSE,proto3" json:"ProofSE,omitempty"` - ProofSR2 []byte `protobuf:"bytes,7,opt,name=ProofSR2,proto3" json:"ProofSR2,omitempty"` - ProofSR3 []byte `protobuf:"bytes,8,opt,name=ProofSR3,proto3" json:"ProofSR3,omitempty"` - ProofSSPrime []byte `protobuf:"bytes,9,opt,name=ProofSSPrime,proto3" json:"ProofSSPrime,omitempty"` - ProofSAttrs [][]byte `protobuf:"bytes,10,rep,name=ProofSAttrs,proto3" json:"ProofSAttrs,omitempty"` - Nonce []byte `protobuf:"bytes,11,opt,name=Nonce,proto3" json:"Nonce,omitempty"` - Nym *ECP `protobuf:"bytes,12,opt,name=Nym" json:"Nym,omitempty"` - ProofSRNym []byte `protobuf:"bytes,13,opt,name=ProofSRNym,proto3" json:"ProofSRNym,omitempty"` + APrime *ECP `protobuf:"bytes,1,opt,name=APrime" json:"APrime,omitempty"` + ABar *ECP `protobuf:"bytes,2,opt,name=ABar" json:"ABar,omitempty"` + BPrime *ECP `protobuf:"bytes,3,opt,name=BPrime" json:"BPrime,omitempty"` + ProofC []byte `protobuf:"bytes,4,opt,name=ProofC,proto3" json:"ProofC,omitempty"` + ProofSSk []byte `protobuf:"bytes,5,opt,name=ProofSSk,proto3" json:"ProofSSk,omitempty"` + ProofSE []byte `protobuf:"bytes,6,opt,name=ProofSE,proto3" json:"ProofSE,omitempty"` + ProofSR2 []byte `protobuf:"bytes,7,opt,name=ProofSR2,proto3" json:"ProofSR2,omitempty"` + ProofSR3 []byte `protobuf:"bytes,8,opt,name=ProofSR3,proto3" json:"ProofSR3,omitempty"` + ProofSSPrime []byte `protobuf:"bytes,9,opt,name=ProofSSPrime,proto3" json:"ProofSSPrime,omitempty"` + ProofSAttrs [][]byte `protobuf:"bytes,10,rep,name=ProofSAttrs,proto3" json:"ProofSAttrs,omitempty"` + Nonce []byte `protobuf:"bytes,11,opt,name=Nonce,proto3" json:"Nonce,omitempty"` + Nym *ECP `protobuf:"bytes,12,opt,name=Nym" json:"Nym,omitempty"` + ProofSRNym []byte `protobuf:"bytes,13,opt,name=ProofSRNym,proto3" json:"ProofSRNym,omitempty"` + RevocationPK *ECP2 `protobuf:"bytes,14,opt,name=RevocationPK" json:"RevocationPK,omitempty"` + RevocationPKSig []byte `protobuf:"bytes,15,opt,name=RevocationPKSig,proto3" json:"RevocationPKSig,omitempty"` + Epoch int64 `protobuf:"varint,16,opt,name=Epoch" json:"Epoch,omitempty"` + NonRevokedProof *NonRevokedProof `protobuf:"bytes,17,opt,name=NonRevokedProof" json:"NonRevokedProof,omitempty"` } func (m *Signature) Reset() { *m = Signature{} } @@ -446,6 +455,95 @@ func (m *Signature) GetProofSRNym() []byte { return nil } +func (m *Signature) GetRevocationPK() *ECP2 { + if m != nil { + return m.RevocationPK + } + return nil +} + +func (m *Signature) GetRevocationPKSig() []byte { + if m != nil { + return m.RevocationPKSig + } + return nil +} + +func (m *Signature) GetEpoch() int64 { + if m != nil { + return m.Epoch + } + return 0 +} + +func (m *Signature) GetNonRevokedProof() *NonRevokedProof { + if m != nil { + return m.NonRevokedProof + } + return nil +} + +// NonRevokedProof contains proof that the credential is not revoked +type NonRevokedProof struct { + RevocationAlg int32 `protobuf:"varint,1,opt,name=RevocationAlg" json:"RevocationAlg,omitempty"` + NonRevokedProof []byte `protobuf:"bytes,2,opt,name=NonRevokedProof,proto3" json:"NonRevokedProof,omitempty"` +} + +func (m *NonRevokedProof) Reset() { *m = NonRevokedProof{} } +func (m *NonRevokedProof) String() string { return proto.CompactTextString(m) } +func (*NonRevokedProof) ProtoMessage() {} +func (*NonRevokedProof) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +func (m *NonRevokedProof) GetRevocationAlg() int32 { + if m != nil { + return m.RevocationAlg + } + return 0 +} + +func (m *NonRevokedProof) GetNonRevokedProof() []byte { + if m != nil { + return m.NonRevokedProof + } + return nil +} + +// PlainSigNonRevokedProof is a non-revoked proof for the plain signature-based revocation algorithm. +// It proves that the revocation authority placed a weak Boneh-Boyen signature (ia.cr/2009/221) on its revocation handle, +// using the zero knowledge proof from Camenisch, Drijvers, Hajny: "Scalable Revocation Scheme for Anonymous Credentials +// Based on n-times Unlinkable Proofs" +type PlainSigNonRevokedProof struct { + SigmaPrime *ECP `protobuf:"bytes,1,opt,name=SigmaPrime" json:"SigmaPrime,omitempty"` + SigmaBar *ECP `protobuf:"bytes,2,opt,name=SigmaBar" json:"SigmaBar,omitempty"` + ProofSR []byte `protobuf:"bytes,3,opt,name=ProofSR,proto3" json:"ProofSR,omitempty"` +} + +func (m *PlainSigNonRevokedProof) Reset() { *m = PlainSigNonRevokedProof{} } +func (m *PlainSigNonRevokedProof) String() string { return proto.CompactTextString(m) } +func (*PlainSigNonRevokedProof) ProtoMessage() {} +func (*PlainSigNonRevokedProof) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } + +func (m *PlainSigNonRevokedProof) GetSigmaPrime() *ECP { + if m != nil { + return m.SigmaPrime + } + return nil +} + +func (m *PlainSigNonRevokedProof) GetSigmaBar() *ECP { + if m != nil { + return m.SigmaBar + } + return nil +} + +func (m *PlainSigNonRevokedProof) GetProofSR() []byte { + if m != nil { + return m.ProofSR + } + return nil +} + // NymSignature specifies a signature object that signs a message // with respect to a pseudonym. It differs from the standard idemix.signature in the fact that // the standard signature object also proves that the pseudonym is based on a secret certified by @@ -465,7 +563,7 @@ type NymSignature struct { func (m *NymSignature) Reset() { *m = NymSignature{} } func (m *NymSignature) String() string { return proto.CompactTextString(m) } func (*NymSignature) ProtoMessage() {} -func (*NymSignature) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } +func (*NymSignature) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } func (m *NymSignature) GetProofC() []byte { if m != nil { @@ -495,6 +593,105 @@ func (m *NymSignature) GetNonce() []byte { return nil } +type CredentialRevocationInformation struct { + // Epoch contains the epoch (time window) in which this CRI is valid + Epoch int64 `protobuf:"varint,1,opt,name=Epoch" json:"Epoch,omitempty"` + // EpochPK is the public key that is used by the revocation authority in this epoch + EpochPK *ECP2 `protobuf:"bytes,2,opt,name=EpochPK" json:"EpochPK,omitempty"` + // EpochPKSig is a signature on the EpochPK valid under the revocation authority's long term key + EpochPKSig []byte `protobuf:"bytes,3,opt,name=EpochPKSig,proto3" json:"EpochPKSig,omitempty"` + // RevocationAlg denotes which revocation algorithm is used + RevocationAlg int32 `protobuf:"varint,4,opt,name=RevocationAlg" json:"RevocationAlg,omitempty"` + // RevocationData contains data specific to the revocation algorithm used + RevocationData []byte `protobuf:"bytes,5,opt,name=RevocationData,proto3" json:"RevocationData,omitempty"` +} + +func (m *CredentialRevocationInformation) Reset() { *m = CredentialRevocationInformation{} } +func (m *CredentialRevocationInformation) String() string { return proto.CompactTextString(m) } +func (*CredentialRevocationInformation) ProtoMessage() {} +func (*CredentialRevocationInformation) Descriptor() ([]byte, []int) { + return fileDescriptor0, []int{10} +} + +func (m *CredentialRevocationInformation) GetEpoch() int64 { + if m != nil { + return m.Epoch + } + return 0 +} + +func (m *CredentialRevocationInformation) GetEpochPK() *ECP2 { + if m != nil { + return m.EpochPK + } + return nil +} + +func (m *CredentialRevocationInformation) GetEpochPKSig() []byte { + if m != nil { + return m.EpochPKSig + } + return nil +} + +func (m *CredentialRevocationInformation) GetRevocationAlg() int32 { + if m != nil { + return m.RevocationAlg + } + return 0 +} + +func (m *CredentialRevocationInformation) GetRevocationData() []byte { + if m != nil { + return m.RevocationData + } + return nil +} + +// PlainSigRevocationData holds the algorithm-specific data for the plain signature-based revocation algorithm +type PlainSigRevocationData struct { + // Signatures contains a list of signed revocation handles + Signatures []*MessageSignature `protobuf:"bytes,1,rep,name=Signatures" json:"Signatures,omitempty"` +} + +func (m *PlainSigRevocationData) Reset() { *m = PlainSigRevocationData{} } +func (m *PlainSigRevocationData) String() string { return proto.CompactTextString(m) } +func (*PlainSigRevocationData) ProtoMessage() {} +func (*PlainSigRevocationData) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } + +func (m *PlainSigRevocationData) GetSignatures() []*MessageSignature { + if m != nil { + return m.Signatures + } + return nil +} + +type MessageSignature struct { + // RevocationHandle is the revocation handle signed + RevocationHandle []byte `protobuf:"bytes,1,opt,name=RevocationHandle,proto3" json:"RevocationHandle,omitempty"` + // RHSignature is the signature on the revocation handle + RHSignature *ECP `protobuf:"bytes,2,opt,name=RHSignature" json:"RHSignature,omitempty"` +} + +func (m *MessageSignature) Reset() { *m = MessageSignature{} } +func (m *MessageSignature) String() string { return proto.CompactTextString(m) } +func (*MessageSignature) ProtoMessage() {} +func (*MessageSignature) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } + +func (m *MessageSignature) GetRevocationHandle() []byte { + if m != nil { + return m.RevocationHandle + } + return nil +} + +func (m *MessageSignature) GetRHSignature() *ECP { + if m != nil { + return m.RHSignature + } + return nil +} + func init() { proto.RegisterType((*ECP)(nil), "ECP") proto.RegisterType((*ECP2)(nil), "ECP2") @@ -503,48 +700,69 @@ func init() { proto.RegisterType((*Credential)(nil), "Credential") proto.RegisterType((*CredRequest)(nil), "CredRequest") proto.RegisterType((*Signature)(nil), "Signature") + proto.RegisterType((*NonRevokedProof)(nil), "NonRevokedProof") + proto.RegisterType((*PlainSigNonRevokedProof)(nil), "PlainSigNonRevokedProof") proto.RegisterType((*NymSignature)(nil), "NymSignature") + proto.RegisterType((*CredentialRevocationInformation)(nil), "CredentialRevocationInformation") + proto.RegisterType((*PlainSigRevocationData)(nil), "PlainSigRevocationData") + proto.RegisterType((*MessageSignature)(nil), "MessageSignature") } func init() { proto.RegisterFile("idemix/idemix.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 591 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x54, 0x4d, 0x6b, 0xdb, 0x4c, - 0x18, 0x64, 0xf5, 0xe1, 0xc4, 0x8f, 0xf5, 0xe6, 0x0d, 0x9b, 0x12, 0x96, 0x50, 0x8a, 0x2b, 0x4a, - 0xc8, 0xc9, 0x21, 0xca, 0x2f, 0x90, 0x8c, 0x5a, 0x87, 0x82, 0x11, 0xd2, 0x21, 0x76, 0x6f, 0xb2, - 0xbd, 0xb6, 0x85, 0x2d, 0x2b, 0x5d, 0x49, 0x10, 0xff, 0x8e, 0x5e, 0xfb, 0x4f, 0x7b, 0x29, 0xfb, - 0xa1, 0x4f, 0xe8, 0xc9, 0x9a, 0x19, 0x3d, 0xfb, 0x8c, 0x67, 0x16, 0xc1, 0x4d, 0xb2, 0xa1, 0x69, - 0xf2, 0xfe, 0x28, 0x7f, 0x26, 0x6f, 0x2c, 0x2b, 0x32, 0xfb, 0x33, 0xe8, 0xfe, 0x34, 0xc0, 0x16, - 0xa0, 0x05, 0x41, 0x63, 0xf4, 0x60, 0x85, 0x68, 0xc1, 0xd1, 0x92, 0x68, 0x12, 0x2d, 0xed, 0xaf, - 0x60, 0xf8, 0xd3, 0xc0, 0xc1, 0x57, 0xa0, 0x2d, 0x5c, 0xf5, 0x92, 0xb6, 0x70, 0x05, 0xf6, 0xd4, - 0x6b, 0xda, 0xc2, 0xe3, 0x78, 0xe9, 0x12, 0x5d, 0xe2, 0xa5, 0xd0, 0x97, 0x1e, 0x31, 0x14, 0xf6, - 0xec, 0xdf, 0x1a, 0xfc, 0xff, 0x92, 0xe7, 0x25, 0x65, 0x41, 0xb9, 0x3a, 0x26, 0xeb, 0xef, 0xf4, - 0x8c, 0xef, 0xe1, 0xca, 0x2d, 0x0a, 0x96, 0xac, 0xca, 0x82, 0xce, 0xe3, 0x94, 0xe6, 0x04, 0x8d, - 0xf5, 0x87, 0x61, 0xd8, 0x63, 0xf1, 0x2d, 0xe8, 0xb3, 0xe8, 0x20, 0x96, 0x8d, 0x1c, 0x63, 0xe2, - 0x4f, 0x83, 0x90, 0x13, 0xf8, 0x0e, 0xcc, 0x59, 0x18, 0x9f, 0x36, 0x62, 0x6d, 0xa5, 0x48, 0x0a, - 0x7f, 0x84, 0xc1, 0x8c, 0x1f, 0x93, 0x13, 0x63, 0xac, 0xd7, 0xa2, 0xe2, 0xf0, 0x0d, 0xa0, 0x57, - 0x62, 0x8a, 0x29, 0x93, 0x0b, 0x4e, 0x88, 0x5e, 0xf9, 0x71, 0x5e, 0xcc, 0xbe, 0x3d, 0x91, 0x41, - 0xfb, 0x38, 0x41, 0x55, 0x9a, 0x43, 0x2e, 0xfa, 0x9a, 0x83, 0x6f, 0x61, 0x10, 0xb0, 0x2c, 0xdb, - 0x4e, 0xc9, 0xa5, 0xf8, 0xbb, 0x0a, 0xd5, 0x7c, 0x44, 0x86, 0x2d, 0x3e, 0xc2, 0x18, 0x8c, 0x59, - 0x9c, 0xef, 0x09, 0x08, 0x56, 0x3c, 0xdb, 0x2e, 0x0c, 0x65, 0x3a, 0x3c, 0x97, 0x6b, 0xd0, 0x5f, - 0xa2, 0x83, 0x0a, 0x9b, 0x3f, 0x62, 0x1b, 0xf4, 0x97, 0xa0, 0x4a, 0xe0, 0x7a, 0xd2, 0x0b, 0x32, - 0xe4, 0xa2, 0xbd, 0x05, 0x98, 0x32, 0xba, 0xa1, 0xa7, 0x22, 0x89, 0x8f, 0x18, 0x03, 0x92, 0x75, - 0x55, 0x66, 0x91, 0xcb, 0x39, 0xaf, 0x93, 0x22, 0xf2, 0x78, 0xdb, 0xbe, 0xaa, 0x0d, 0xf9, 0x1c, - 0x45, 0xaa, 0x34, 0x14, 0xe1, 0x0f, 0x60, 0xca, 0x08, 0xcd, 0xb1, 0xfe, 0x60, 0x85, 0x12, 0xd8, - 0xbf, 0x10, 0x8c, 0xf8, 0xa2, 0x90, 0xfe, 0x2c, 0x69, 0x5e, 0xf0, 0x76, 0xe6, 0xe7, 0xb4, 0xb3, - 0x8b, 0x13, 0x78, 0x0c, 0x23, 0xe9, 0x73, 0x9e, 0x9d, 0xd6, 0x54, 0x5d, 0x95, 0x36, 0xd5, 0x0a, - 0x4e, 0xef, 0x04, 0x47, 0xe0, 0x42, 0x46, 0xf5, 0xa4, 0xbc, 0x54, 0xb0, 0x51, 0x1c, 0xd1, 0x5e, - 0xad, 0x38, 0xf6, 0x1f, 0x0d, 0x86, 0x51, 0xb2, 0x3b, 0xc5, 0x45, 0xc9, 0x28, 0x6f, 0xdf, 0x0d, - 0x58, 0x92, 0xd2, 0x8e, 0x2d, 0xc5, 0x61, 0x02, 0x86, 0xeb, 0xc5, 0xac, 0x13, 0x85, 0x60, 0xf8, - 0x9c, 0x27, 0xe7, 0xda, 0x57, 0x4a, 0x71, 0x2d, 0xbf, 0x46, 0xc7, 0xef, 0x1d, 0x5c, 0x4a, 0x1b, - 0xd1, 0x41, 0xd9, 0xaa, 0x71, 0xe3, 0xd8, 0x17, 0xd7, 0xaa, 0x76, 0xec, 0x37, 0x53, 0xa1, 0xbc, - 0x55, 0xf5, 0x54, 0xe8, 0xb4, 0xb4, 0x67, 0x75, 0xa9, 0x6a, 0x8c, 0x6d, 0xb0, 0xd4, 0xe9, 0xd2, - 0xa9, 0xbc, 0x5c, 0x1d, 0x8e, 0x67, 0x2f, 0xb1, 0xec, 0x0f, 0x44, 0x7f, 0x6d, 0x8a, 0x77, 0x2b, - 0x7b, 0x19, 0x89, 0x71, 0xb3, 0x6a, 0x44, 0x74, 0x69, 0xf5, 0xbb, 0xfc, 0x04, 0xa0, 0xf6, 0x73, - 0xf9, 0x3f, 0x31, 0xd2, 0x62, 0xec, 0x77, 0xb0, 0xe6, 0xe7, 0xb4, 0xc9, 0xbf, 0x49, 0x0a, 0xfd, - 0x33, 0x29, 0xad, 0x97, 0x54, 0x77, 0x87, 0xde, 0xdf, 0xd1, 0x38, 0x36, 0x5a, 0x8e, 0xbd, 0xfb, - 0x1f, 0x5f, 0x76, 0x49, 0xb1, 0x2f, 0x57, 0x93, 0x75, 0x96, 0x3e, 0xee, 0xcf, 0x6f, 0x94, 0x1d, - 0xe9, 0x66, 0x47, 0xd9, 0xe3, 0x36, 0x5e, 0xb1, 0x64, 0xad, 0x3e, 0x78, 0xab, 0x81, 0xf8, 0xe2, - 0x3d, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x06, 0x88, 0xd9, 0x9e, 0x08, 0x05, 0x00, 0x00, + // 842 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x55, 0x4d, 0x6f, 0xe3, 0x36, + 0x14, 0x04, 0x2d, 0x39, 0x1f, 0xcf, 0xde, 0xc4, 0xcb, 0x2d, 0x52, 0x62, 0x51, 0x74, 0x5d, 0x61, + 0x11, 0xb8, 0x3d, 0x38, 0x88, 0xf6, 0xd6, 0x9b, 0xe4, 0xba, 0x75, 0x10, 0xd4, 0x10, 0xa8, 0xc3, + 0xda, 0xbd, 0xd1, 0x36, 0xed, 0x08, 0xb1, 0xa4, 0x54, 0x92, 0x8b, 0x18, 0xfd, 0x19, 0xbd, 0xf6, + 0xd4, 0x1f, 0xd3, 0xdf, 0x55, 0xf0, 0x43, 0x12, 0x25, 0x77, 0x4f, 0xe1, 0xcc, 0x23, 0xf9, 0xc6, + 0x6f, 0x86, 0x11, 0xbc, 0x8b, 0x36, 0x3c, 0x8e, 0x5e, 0xef, 0xd4, 0x9f, 0xf1, 0x4b, 0x96, 0x16, + 0xa9, 0xf3, 0x1d, 0x58, 0xd3, 0x49, 0x80, 0xfb, 0x80, 0x16, 0x04, 0x0d, 0xd1, 0xa8, 0x4f, 0xd1, + 0x42, 0xa0, 0x25, 0xe9, 0x28, 0xb4, 0x74, 0x7e, 0x06, 0x7b, 0x3a, 0x09, 0x5c, 0x7c, 0x05, 0x9d, + 0x85, 0xa7, 0x37, 0x75, 0x16, 0x9e, 0xc4, 0xbe, 0xde, 0xd6, 0x59, 0xf8, 0x02, 0x2f, 0x3d, 0x62, + 0x29, 0xbc, 0x94, 0xf5, 0xa5, 0x4f, 0x6c, 0x8d, 0x7d, 0xe7, 0xef, 0x0e, 0x5c, 0x3f, 0xe4, 0xf9, + 0x81, 0x67, 0xc1, 0x61, 0xb5, 0x8f, 0xd6, 0x8f, 0xfc, 0x88, 0x6f, 0xe1, 0xca, 0x2b, 0x8a, 0x2c, + 0x5a, 0x1d, 0x0a, 0x3e, 0x67, 0x31, 0xcf, 0x09, 0x1a, 0x5a, 0xa3, 0x4b, 0xda, 0x62, 0xf1, 0x0d, + 0x58, 0xb3, 0xf0, 0x59, 0x36, 0xeb, 0xb9, 0xf6, 0x78, 0x3a, 0x09, 0xa8, 0x20, 0xf0, 0x7b, 0xe8, + 0xce, 0x28, 0x4b, 0x36, 0xb2, 0x6d, 0x59, 0x51, 0x14, 0xfe, 0x06, 0xce, 0x66, 0xe2, 0x9a, 0x9c, + 0xd8, 0x43, 0xab, 0x2a, 0x6a, 0x0e, 0xbf, 0x03, 0xf4, 0x99, 0x74, 0xe5, 0xa9, 0xae, 0x28, 0xb8, + 0x14, 0x7d, 0x16, 0xd7, 0xf9, 0x2c, 0xfb, 0xe5, 0x9e, 0x9c, 0x99, 0xd7, 0x49, 0xaa, 0xac, 0xb9, + 0xe4, 0xbc, 0x5d, 0x73, 0xf1, 0x0d, 0x9c, 0x05, 0x59, 0x9a, 0x6e, 0x27, 0xe4, 0x42, 0xfe, 0x5c, + 0x8d, 0x2a, 0x3e, 0x24, 0x97, 0x06, 0x1f, 0x62, 0x0c, 0xf6, 0x8c, 0xe5, 0x4f, 0x04, 0x24, 0x2b, + 0xd7, 0x8e, 0x07, 0x97, 0x6a, 0x3a, 0x62, 0x2e, 0x03, 0xb0, 0x1e, 0xc2, 0x67, 0x3d, 0x6c, 0xb1, + 0xc4, 0x0e, 0x58, 0x0f, 0x41, 0x39, 0x81, 0xc1, 0xb8, 0x35, 0x48, 0x2a, 0x8a, 0xce, 0x16, 0x60, + 0x92, 0xf1, 0x0d, 0x4f, 0x8a, 0x88, 0xed, 0x31, 0x06, 0xa4, 0xec, 0x2a, 0xc5, 0x22, 0x4f, 0x70, + 0x7e, 0x63, 0x8a, 0xc8, 0x17, 0x6e, 0x4f, 0xb5, 0x6d, 0x68, 0x2a, 0x50, 0xa8, 0x4d, 0x43, 0x21, + 0xfe, 0x0a, 0xba, 0x6a, 0x84, 0xdd, 0xa1, 0x35, 0xea, 0x53, 0x05, 0x9c, 0xbf, 0x10, 0xf4, 0x44, + 0x23, 0xca, 0x7f, 0x3f, 0xf0, 0xbc, 0x10, 0xee, 0xcc, 0x8f, 0x71, 0xa3, 0x97, 0x20, 0xf0, 0x10, + 0x7a, 0x4a, 0xe7, 0x3c, 0x4d, 0xd6, 0x5c, 0x47, 0xc5, 0xa4, 0x8c, 0xc1, 0x59, 0x8d, 0xc1, 0x11, + 0x38, 0x57, 0xa3, 0xba, 0xd7, 0x5a, 0x4a, 0x58, 0x57, 0x5c, 0xe9, 0x5e, 0x55, 0x71, 0x9d, 0x7f, + 0x6c, 0xb8, 0x0c, 0xa3, 0x5d, 0xc2, 0x8a, 0x43, 0xc6, 0x85, 0xfb, 0x5e, 0x90, 0x45, 0x31, 0x6f, + 0xc8, 0xd2, 0x1c, 0x26, 0x60, 0x7b, 0x3e, 0xcb, 0x1a, 0xa3, 0x90, 0x8c, 0x38, 0xe7, 0xab, 0x73, + 0x66, 0xa4, 0x34, 0x67, 0xe8, 0xb5, 0x1b, 0x7a, 0xdf, 0xc3, 0x85, 0x92, 0x11, 0x3e, 0x6b, 0x59, + 0x15, 0xae, 0x15, 0x4f, 0x65, 0xac, 0x2a, 0xc5, 0xd3, 0xfa, 0x14, 0x55, 0xa9, 0xaa, 0x4e, 0x51, + 0xd7, 0xa8, 0x7d, 0xd2, 0xa1, 0xaa, 0x30, 0x76, 0xa0, 0xaf, 0x6f, 0x57, 0x4a, 0x55, 0xb8, 0x1a, + 0x9c, 0x98, 0xbd, 0xc2, 0xca, 0x3f, 0x90, 0xfe, 0x99, 0x94, 0xf0, 0x56, 0xf9, 0xd2, 0x93, 0xc7, + 0xbb, 0xa5, 0x23, 0xd2, 0xcb, 0x7e, 0xdb, 0xcb, 0x6f, 0x01, 0x74, 0x7f, 0x51, 0x7e, 0x23, 0x8f, + 0x18, 0x0c, 0xfe, 0x1e, 0xfa, 0x94, 0xff, 0x91, 0xae, 0x59, 0x11, 0xa5, 0x49, 0xf0, 0x48, 0xae, + 0xcc, 0xa7, 0xd5, 0x28, 0xe1, 0x11, 0x5c, 0x9b, 0x38, 0x8c, 0x76, 0xe4, 0x5a, 0xde, 0xd7, 0xa6, + 0x85, 0xc4, 0xe9, 0x4b, 0xba, 0x7e, 0x22, 0x83, 0x21, 0x1a, 0x59, 0x54, 0x01, 0xfc, 0x23, 0x5c, + 0xcf, 0xd3, 0x44, 0xec, 0x7d, 0xe6, 0x1b, 0x29, 0x81, 0xbc, 0xd5, 0xcf, 0xa2, 0xc5, 0xd3, 0xf6, + 0x46, 0x87, 0x9d, 0x9c, 0xc5, 0x1f, 0xe1, 0x4d, 0xdd, 0xd7, 0xdb, 0xef, 0x64, 0x60, 0xba, 0xb4, + 0x49, 0x0a, 0xd1, 0xed, 0xa6, 0x2a, 0xcf, 0x27, 0x2d, 0xfe, 0x84, 0xaf, 0x83, 0x3d, 0x8b, 0x92, + 0x30, 0xda, 0x9d, 0xb6, 0x82, 0x30, 0xda, 0xc5, 0xec, 0x34, 0x98, 0x06, 0x8f, 0x87, 0x70, 0x21, + 0x51, 0x3b, 0xa0, 0x15, 0x5b, 0x47, 0x8a, 0xea, 0x77, 0x53, 0x42, 0xe7, 0x15, 0xfa, 0xf3, 0x63, + 0x5c, 0x3f, 0x83, 0x3a, 0xb0, 0xe8, 0x8b, 0x81, 0xed, 0xb4, 0x02, 0xdb, 0xb4, 0xda, 0x3a, 0xb1, + 0xba, 0x0a, 0x8e, 0x6d, 0x04, 0xc7, 0xf9, 0x17, 0xc1, 0x87, 0xfa, 0xbf, 0x4f, 0x3d, 0xbc, 0x87, + 0x64, 0x9b, 0x66, 0xb1, 0x5c, 0xd6, 0x7e, 0x22, 0xd3, 0xcf, 0x0f, 0x70, 0x2e, 0x17, 0xc1, 0xa3, + 0xfe, 0xb9, 0x3a, 0x35, 0x25, 0x2b, 0x04, 0xe9, 0xa5, 0xc8, 0x8a, 0x16, 0x54, 0x33, 0xa7, 0x0e, + 0xda, 0xff, 0xe7, 0xe0, 0x2d, 0x5c, 0xd5, 0xc4, 0x4f, 0xac, 0x60, 0xfa, 0xa5, 0xb6, 0x58, 0xe7, + 0x11, 0x6e, 0x4a, 0xff, 0x9a, 0x15, 0x7c, 0x2f, 0xed, 0x53, 0x93, 0x55, 0x5f, 0xaa, 0x9e, 0xfb, + 0x76, 0xfc, 0x2b, 0xcf, 0x73, 0xb6, 0xe3, 0x55, 0x85, 0x1a, 0x9b, 0x9c, 0x2d, 0x0c, 0xda, 0x75, + 0xfc, 0x03, 0x0c, 0xea, 0x8b, 0x67, 0x2c, 0xd9, 0xec, 0xb9, 0x76, 0xe7, 0x84, 0xc7, 0xb7, 0xd0, + 0xa3, 0xb3, 0xea, 0x68, 0x23, 0x0e, 0x66, 0xc1, 0xbf, 0xfd, 0xed, 0xe3, 0x2e, 0x2a, 0x9e, 0x0e, + 0xab, 0xf1, 0x3a, 0x8d, 0xef, 0x9e, 0x8e, 0x2f, 0x3c, 0xdb, 0xf3, 0xcd, 0x8e, 0x67, 0x77, 0x5b, + 0xb6, 0xca, 0xa2, 0xb5, 0xfe, 0xea, 0xaf, 0xce, 0xe4, 0x67, 0xff, 0xd3, 0x7f, 0x01, 0x00, 0x00, + 0xff, 0xff, 0x5c, 0xff, 0x50, 0x60, 0x0d, 0x08, 0x00, 0x00, } diff --git a/vendor/github.com/hyperledger/fabric/idemix/nonrevoked-prover.go b/vendor/github.com/hyperledger/fabric/idemix/nonrevoked-prover.go new file mode 100644 index 000000000..53ec3b793 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric/idemix/nonrevoked-prover.go @@ -0,0 +1,116 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package idemix + +import ( + "reflect" + + "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric-amcl/amcl" + "github.com/hyperledger/fabric-amcl/amcl/FP256BN" + "github.com/pkg/errors" +) + +type nonRevokedProver interface { + getFSContribution(rh *FP256BN.BIG, rRh *FP256BN.BIG, cri *CredentialRevocationInformation, rng *amcl.RAND) ([]byte, error) + getNonRevokedProof(chal *FP256BN.BIG) (*NonRevokedProof, error) +} +type nopNonRevokedProver struct{} + +func (prover *nopNonRevokedProver) getFSContribution(rh *FP256BN.BIG, rRh *FP256BN.BIG, cri *CredentialRevocationInformation, rng *amcl.RAND) ([]byte, error) { + return nil, nil +} +func (prover *nopNonRevokedProver) getNonRevokedProof(chal *FP256BN.BIG) (*NonRevokedProof, error) { + ret := &NonRevokedProof{} + ret.RevocationAlg = int32(ALG_NO_REVOCATION) + return ret, nil +} + +func getNonRevocationProver(algorithm RevocationAlgorithm) (nonRevokedProver, error) { + switch algorithm { + case ALG_NO_REVOCATION: + return &nopNonRevokedProver{}, nil + case ALG_PLAIN_SIGNATURE: + return &plainSigNonRevokedProver{}, nil + default: + // unknown revocation algorithm + return nil, errors.Errorf("unknown revocation algorithm %d", algorithm) + } +} + +type plainSigNonRevokedProver struct { + rh *FP256BN.BIG // revocation handle + rRh *FP256BN.BIG // r-value used in proving knowledge of rh + sig *FP256BN.ECP // signature on rh + randSig *FP256BN.BIG // randomness used to randomize sig + rRandSig *FP256BN.BIG // r-value used in proving knowledge of randSig + sigPrime *FP256BN.ECP // sig^randSig + sigBar *FP256BN.ECP // sigPrime^-rh * genG1^randSig +} + +func (prover *plainSigNonRevokedProver) getFSContribution(rh *FP256BN.BIG, rRh *FP256BN.BIG, cri *CredentialRevocationInformation, rng *amcl.RAND) ([]byte, error) { + if cri.RevocationAlg != int32(ALG_PLAIN_SIGNATURE) { + return nil, errors.Errorf("the credential revocation revocation is not for ALG_PLAIN_SIGNATURE") + } + revocationData := &PlainSigRevocationData{} + err := proto.Unmarshal(cri.RevocationData, revocationData) + if err != nil { + return nil, errors.Wrap(err, "failed to unmarshal revocation data") + } + + prover.rh = rh + prover.rRh = rRh + rhBytes := BigToBytes(rh) + + for _, m := range revocationData.Signatures { + if reflect.DeepEqual(rhBytes, m.RevocationHandle) { + prover.sig = EcpFromProto(m.RHSignature) + break + } + } + if prover.sig == nil { + return nil, errors.Errorf("no signature for the revocation handle found in the cri, signer is probably revoked") + } + + // prove knowledge of sig with the ZKP from Camenisch-Drijvers-Hajny: "Scalable Revocation Scheme + // for Anonymous Credentials Based on n-times Unlinkable Proofs" + prover.randSig = RandModOrder(rng) + prover.sigPrime = prover.sig.Mul(prover.randSig) + prover.sigBar = prover.sigPrime.Mul2(FP256BN.Modneg(prover.rh, GroupOrder), GenG1, prover.randSig) + prover.rRandSig = RandModOrder(rng) + + t := prover.sigPrime.Mul2(FP256BN.Modneg(prover.rRh, GroupOrder), GenG1, prover.rRandSig) + + // fsBytes will hold three elements of G1, each taking 2*FieldBytes+1 bytes, and one element of G2, which takes 4*FieldBytes + fsBytes := make([]byte, 3*(2*FieldBytes+1)+4*FieldBytes) + index := appendBytesG1(fsBytes, 0, prover.sigBar) + index = appendBytesG1(fsBytes, index, prover.sigPrime) + index = appendBytesG2(fsBytes, index, Ecp2FromProto(cri.EpochPK)) + index = appendBytesG1(fsBytes, index, t) + + return fsBytes, nil +} + +func (prover *plainSigNonRevokedProver) getNonRevokedProof(chal *FP256BN.BIG) (*NonRevokedProof, error) { + ret := &NonRevokedProof{} + ret.RevocationAlg = int32(ALG_PLAIN_SIGNATURE) + + proof := &PlainSigNonRevokedProof{} + + proof.ProofSR = BigToBytes(Modadd(prover.rRandSig, FP256BN.Modmul(prover.randSig, chal, GroupOrder), GroupOrder)) + proof.SigmaBar = EcpToProto(prover.sigBar) + proof.SigmaPrime = EcpToProto(prover.sigPrime) + + b, err := proto.Marshal(proof) + if err != nil { + return nil, err + } + + ret.NonRevokedProof = b + + return ret, nil +} diff --git a/vendor/github.com/hyperledger/fabric/idemix/nonrevoked-verifier.go b/vendor/github.com/hyperledger/fabric/idemix/nonrevoked-verifier.go new file mode 100644 index 000000000..94a87f958 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric/idemix/nonrevoked-verifier.go @@ -0,0 +1,71 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package idemix + +import ( + "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric-amcl/amcl/FP256BN" + "github.com/pkg/errors" +) + +type nonRevokedVerifier interface { + recomputeFSContribution(proof *NonRevokedProof, chal *FP256BN.BIG, epochPK *FP256BN.ECP2, proofSRh *FP256BN.BIG) ([]byte, error) +} +type nopNonRevokedVerifier struct{} + +func (verifier *nopNonRevokedVerifier) recomputeFSContribution(proof *NonRevokedProof, chal *FP256BN.BIG, epochPK *FP256BN.ECP2, proofSRh *FP256BN.BIG) ([]byte, error) { + return nil, nil +} + +func getNonRevocationVerifier(algorithm RevocationAlgorithm) (nonRevokedVerifier, error) { + switch algorithm { + case ALG_NO_REVOCATION: + return &nopNonRevokedVerifier{}, nil + case ALG_PLAIN_SIGNATURE: + return &plainSigNonRevokedVerifier{}, nil + default: + // unknown revocation algorithm + return nil, errors.Errorf("unknown revocation algorithm %d", algorithm) + } +} + +type plainSigNonRevokedVerifier struct{} + +func (verifier *plainSigNonRevokedVerifier) recomputeFSContribution(proof *NonRevokedProof, chal *FP256BN.BIG, epochPK *FP256BN.ECP2, proofSRh *FP256BN.BIG) ([]byte, error) { + proofUnmarshaled := &PlainSigNonRevokedProof{} + err := proto.Unmarshal(proof.NonRevokedProof, proofUnmarshaled) + if err != nil { + return nil, errors.Wrap(err, "Failed to unmarshal non-revoked proof") + } + + sigBar := EcpFromProto(proofUnmarshaled.SigmaBar) + sigPrime := EcpFromProto(proofUnmarshaled.SigmaPrime) + if sigPrime.Is_infinity() { + return nil, errors.Errorf("Nonrevoked proof is invalid, sigPrime = 1") + } + + // Check whether sigBar and sigPrime have the right structure + minSigPrime := FP256BN.NewECP() + minSigPrime.Sub(sigPrime) + + result := FP256BN.Fexp(FP256BN.Ate2(epochPK, minSigPrime, GenG2, sigBar)) + if !result.Isunity() { + return nil, errors.Errorf("SigmaBar and SigmaPrime don't have the expected structure") + } + + t := sigPrime.Mul2(FP256BN.Modneg(proofSRh, GroupOrder), GenG1, FP256BN.FromBytes(proofUnmarshaled.ProofSR)) + t.Sub(sigBar.Mul(chal)) + + // fsBytes will hold three elements of G1, each taking 2*FieldBytes+1 bytes, and one element of G2, which takes 4*FieldBytes + fsBytes := make([]byte, 3*(2*FieldBytes+1)+4*FieldBytes) + index := appendBytesG1(fsBytes, 0, sigBar) + index = appendBytesG1(fsBytes, index, sigPrime) + index = appendBytesG2(fsBytes, index, epochPK) + index = appendBytesG1(fsBytes, index, t) + + return fsBytes, nil +} diff --git a/vendor/github.com/hyperledger/fabric/idemix/revocation_authority.go b/vendor/github.com/hyperledger/fabric/idemix/revocation_authority.go new file mode 100644 index 000000000..24a19daf2 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric/idemix/revocation_authority.go @@ -0,0 +1,116 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package idemix + +import ( + "crypto/ecdsa" + + "crypto/rand" + "crypto/sha256" + + "crypto/elliptic" + + "math/big" + + "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric-amcl/amcl" + "github.com/hyperledger/fabric-amcl/amcl/FP256BN" + "github.com/pkg/errors" +) + +type RevocationAlgorithm int32 + +const ( + ALG_NO_REVOCATION RevocationAlgorithm = iota + ALG_PLAIN_SIGNATURE +) + +var ProofBytes = map[RevocationAlgorithm]int{ + ALG_NO_REVOCATION: 0, + ALG_PLAIN_SIGNATURE: 3*(2*FieldBytes+1) + 4*FieldBytes, +} + +// GenerateLongTermRevocationKey generates a long term signing key that will be used for revocation +func GenerateLongTermRevocationKey() (*ecdsa.PrivateKey, error) { + return ecdsa.GenerateKey(elliptic.P384(), rand.Reader) +} + +func CreateCRI(key *ecdsa.PrivateKey, unrevokedHandles []*FP256BN.BIG, epoch int, alg RevocationAlgorithm, rng *amcl.RAND) (*CredentialRevocationInformation, error) { + cri := &CredentialRevocationInformation{} + cri.RevocationAlg = int32(alg) + cri.Epoch = int64(epoch) + + // create epoch key + epochSk, epochPk := WBBKeyGen(rng) + if alg == ALG_NO_REVOCATION { + // put a dummy PK in the proto + cri.EpochPK = Ecp2ToProto(GenG2) + } else { + // only put the epoch pk in the proto if we will actually use it + cri.EpochPK = Ecp2ToProto(epochPk) + } + + // sign epoch + epoch key with long term key + bytesToSign, err := proto.Marshal(cri) + digest := sha256.New().Sum(bytesToSign) + + pkSigR, pkSigS, err := ecdsa.Sign(rand.Reader, key, digest) + if err != nil { + return nil, err + } + cri.EpochPKSig = append(pkSigR.Bytes(), pkSigS.Bytes()...) + + if alg == ALG_NO_REVOCATION { + return cri, nil + } else if alg == ALG_PLAIN_SIGNATURE { + // create revocationData object + revocationData := &PlainSigRevocationData{} + revocationData.Signatures = make([]*MessageSignature, len(unrevokedHandles)) + for i, rh := range unrevokedHandles { + // sign revocation handle + sig := WBBSign(epochSk, rh) + + // store revocation handle and signature in revocationData + revocationData.Signatures[i] = &MessageSignature{BigToBytes(rh), EcpToProto(sig)} + } + + // serialize the algorithm-specific revocation data + revocationDataBytes, err := proto.Marshal(revocationData) + if err != nil { + return nil, err + } + cri.RevocationData = revocationDataBytes + + return cri, nil + } else { + return nil, errors.Errorf("the specified revocation algorithm is not supported.") + } +} + +// VerifyEpochPK verifies that the revocation PK for a certain epoch is valid, +// by checking that it was signed with the long term revocation key +func VerifyEpochPK(pk *ecdsa.PublicKey, epochPK *ECP2, epochPkSig []byte, epoch int, alg RevocationAlgorithm) error { + cri := &CredentialRevocationInformation{} + cri.RevocationAlg = int32(alg) + cri.EpochPK = epochPK + cri.Epoch = int64(epoch) + bytesToSign, err := proto.Marshal(cri) + if err != nil { + return err + } + digest := sha256.New().Sum(bytesToSign) + sigR := &big.Int{} + sigR.SetBytes(epochPkSig[0 : len(epochPkSig)/2]) + sigS := &big.Int{} + sigS.SetBytes(epochPkSig[len(epochPkSig)/2:]) + + if !ecdsa.Verify(pk, digest, sigR, sigS) { + return errors.Errorf("EpochPKSig invalid") + } + + return nil +} diff --git a/vendor/github.com/hyperledger/fabric/idemix/signature.go b/vendor/github.com/hyperledger/fabric/idemix/signature.go index a73e54eab..91738c0a7 100644 --- a/vendor/github.com/hyperledger/fabric/idemix/signature.go +++ b/vendor/github.com/hyperledger/fabric/idemix/signature.go @@ -7,6 +7,10 @@ SPDX-License-Identifier: Apache-2.0 package idemix import ( + "crypto/ecdsa" + + "sort" + "github.com/hyperledger/fabric-amcl/amcl" "github.com/hyperledger/fabric-amcl/amcl/FP256BN" "github.com/pkg/errors" @@ -43,11 +47,15 @@ func hiddenIndices(Disclosure []byte) []int { // The []byte Disclosure steers which attributes are disclosed: // if Disclosure[i] == 0 then attribute i remains hidden and otherwise it is disclosed. // We use the zero-knowledge proof by http://eprint.iacr.org/2016/663.pdf to prove knowledge of a BBS+ signature -func NewSignature(cred *Credential, sk *FP256BN.BIG, Nym *FP256BN.ECP, RNym *FP256BN.BIG, ipk *IssuerPublicKey, Disclosure []byte, msg []byte, rng *amcl.RAND) (*Signature, error) { - if cred == nil || sk == nil || Nym == nil || RNym == nil || ipk == nil || rng == nil { +func NewSignature(cred *Credential, sk *FP256BN.BIG, Nym *FP256BN.ECP, RNym *FP256BN.BIG, ipk *IssuerPublicKey, Disclosure []byte, msg []byte, rhIndex int, cri *CredentialRevocationInformation, rng *amcl.RAND) (*Signature, error) { + if cred == nil || sk == nil || Nym == nil || RNym == nil || ipk == nil || rng == nil || cri == nil { return nil, errors.Errorf("cannot create idemix signature: received nil input") } + if cri.RevocationAlg != int32(ALG_NO_REVOCATION) && Disclosure[rhIndex] == 1 { + return nil, errors.Errorf("Attribute %d is disclosed but also used as revocation handle attribute, which should remain hidden.", rhIndex) + } + HiddenIndices := hiddenIndices(Disclosure) // Start sig @@ -87,6 +95,16 @@ func NewSignature(cred *Credential, sk *FP256BN.BIG, Nym *FP256BN.ECP, RNym *FP2 rAttrs[i] = RandModOrder(rng) } + // compute non-revoked proof + prover, err := getNonRevocationProver(RevocationAlgorithm(cri.RevocationAlg)) + if err != nil { + return nil, err + } + nonRevokedProofHashData, err := prover.getFSContribution(FP256BN.FromBytes(cred.Attrs[rhIndex]), rAttrs[sort.SearchInts(HiddenIndices, rhIndex)], cri, rng) + if err != nil { + return nil, errors.Wrap(err, "failed to compute non-revoked proof") + } + t1 := APrime.Mul2(re, HRand, rR2) t2 := FP256BN.G1mul(HRand, rSPrime) t2.Add(BPrime.Mul2(rR3, HSk, rSk)) @@ -106,7 +124,8 @@ func NewSignature(cred *Credential, sk *FP256BN.BIG, Nym *FP256BN.ECP, RNym *FP2 // one bigint (hash of the issuer public key) of length FieldBytes // disclosed attributes // message being signed - proofData := make([]byte, len([]byte(signLabel))+7*(2*FieldBytes+1)+FieldBytes+len(Disclosure)+len(msg)) + // the amount of bytes needed for the nonrevocation proof + proofData := make([]byte, len([]byte(signLabel))+7*(2*FieldBytes+1)+FieldBytes+len(Disclosure)+len(msg)+ProofBytes[RevocationAlgorithm(cri.RevocationAlg)]) index := 0 index = appendBytesString(proofData, index, signLabel) index = appendBytesG1(proofData, index, t1) @@ -116,6 +135,7 @@ func NewSignature(cred *Credential, sk *FP256BN.BIG, Nym *FP256BN.ECP, RNym *FP2 index = appendBytesG1(proofData, index, ABar) index = appendBytesG1(proofData, index, BPrime) index = appendBytesG1(proofData, index, Nym) + index = appendBytes(proofData, index, nonRevokedProofHashData) copy(proofData[index:], ipk.Hash) index = index + FieldBytes copy(proofData[index:], Disclosure) @@ -141,6 +161,11 @@ func NewSignature(cred *Credential, sk *FP256BN.BIG, Nym *FP256BN.ECP, RNym *FP2 ProofSAttrs[i] = BigToBytes(Modadd(rAttrs[i], FP256BN.Modmul(ProofC, FP256BN.FromBytes(cred.Attrs[j]), GroupOrder), GroupOrder)) } + nonRevokedProof, err := prover.getNonRevokedProof(ProofC) + if err != nil { + return nil, err + } + return &Signature{ EcpToProto(APrime), EcpToProto(ABar), @@ -154,16 +179,29 @@ func NewSignature(cred *Credential, sk *FP256BN.BIG, Nym *FP256BN.ECP, RNym *FP2 ProofSAttrs, BigToBytes(Nonce), EcpToProto(Nym), - BigToBytes(ProofSRNym)}, + BigToBytes(ProofSRNym), + cri.EpochPK, + cri.EpochPKSig, + cri.Epoch, + nonRevokedProof}, nil } // Ver verifies an idemix signature // Disclosure steers which attributes it expects to be disclosed // attributeValues[i] contains the desired attribute value for the i-th undisclosed attribute in Disclosure -func (sig *Signature) Ver(Disclosure []byte, ipk *IssuerPublicKey, msg []byte, attributeValues []*FP256BN.BIG) error { +func (sig *Signature) Ver(Disclosure []byte, ipk *IssuerPublicKey, msg []byte, attributeValues []*FP256BN.BIG, rhIndex int, revPk *ecdsa.PublicKey, epoch int) error { + if sig.NonRevokedProof.RevocationAlg != int32(ALG_NO_REVOCATION) && Disclosure[rhIndex] == 1 { + return errors.Errorf("Attribute %d is disclosed but is also used as revocation handle, which should remain hidden.", rhIndex) + } + HiddenIndices := hiddenIndices(Disclosure) + err := VerifyEpochPK(revPk, sig.RevocationPK, sig.RevocationPKSig, epoch, RevocationAlgorithm(sig.NonRevokedProof.RevocationAlg)) + if err != nil { + return errors.Wrap(err, "signature is based on an invalid revocation epoch public key") + } + APrime := EcpFromProto(sig.GetAPrime()) ABar := EcpFromProto(sig.GetABar()) BPrime := EcpFromProto(sig.GetBPrime()) @@ -230,13 +268,25 @@ func (sig *Signature) Ver(Disclosure []byte, ipk *IssuerPublicKey, msg []byte, a t3 := HSk.Mul2(ProofSSk, HRand, ProofSRNym) t3.Sub(Nym.Mul(ProofC)) + nonRevokedVer, err := getNonRevocationVerifier(RevocationAlgorithm(sig.NonRevokedProof.RevocationAlg)) + if err != nil { + return err + } + + i := sort.SearchInts(HiddenIndices, rhIndex) + proofSRh := ProofSAttrs[i] + nonRevokedProofBytes, err := nonRevokedVer.recomputeFSContribution(sig.NonRevokedProof, ProofC, Ecp2FromProto(sig.RevocationPK), proofSRh) + if err != nil { + return err + } + // proofData is the data being hashed, it consists of: // the signature label // 7 elements of G1 each taking 2*FieldBytes+1 bytes // one bigint (hash of the issuer public key) of length FieldBytes // disclosed attributes // message that was signed - proofData := make([]byte, len([]byte(signLabel))+7*(2*FieldBytes+1)+FieldBytes+len(Disclosure)+len(msg)) + proofData := make([]byte, len([]byte(signLabel))+7*(2*FieldBytes+1)+FieldBytes+len(Disclosure)+len(msg)+ProofBytes[RevocationAlgorithm(sig.NonRevokedProof.RevocationAlg)]) index := 0 index = appendBytesString(proofData, index, signLabel) index = appendBytesG1(proofData, index, t1) @@ -246,6 +296,7 @@ func (sig *Signature) Ver(Disclosure []byte, ipk *IssuerPublicKey, msg []byte, a index = appendBytesG1(proofData, index, ABar) index = appendBytesG1(proofData, index, BPrime) index = appendBytesG1(proofData, index, Nym) + index = appendBytes(proofData, index, nonRevokedProofBytes) copy(proofData[index:], ipk.Hash) index = index + FieldBytes copy(proofData[index:], Disclosure) diff --git a/vendor/github.com/hyperledger/fabric/idemix/util.go b/vendor/github.com/hyperledger/fabric/idemix/util.go index 85a5384df..3156f70b6 100644 --- a/vendor/github.com/hyperledger/fabric/idemix/util.go +++ b/vendor/github.com/hyperledger/fabric/idemix/util.go @@ -25,6 +25,9 @@ var GenG2 = FP256BN.NewECP2fp2s( FP256BN.NewFP2bigs(FP256BN.NewBIGints(FP256BN.CURVE_Pxa), FP256BN.NewBIGints(FP256BN.CURVE_Pxb)), FP256BN.NewFP2bigs(FP256BN.NewBIGints(FP256BN.CURVE_Pya), FP256BN.NewBIGints(FP256BN.CURVE_Pyb))) +// GenGT is a generator of Group GT +var GenGT = FP256BN.Fexp(FP256BN.Ate(GenG2, GenG1)) + // GroupOrder is the order of the groups var GroupOrder = FP256BN.NewBIGints(FP256BN.CURVE_Order) @@ -48,6 +51,10 @@ func HashModOrder(data []byte) *FP256BN.BIG { return digestBig } +func appendBytes(data []byte, index int, bytesToAdd []byte) int { + copy(data[index:], bytesToAdd) + return index + len(bytesToAdd) +} func appendBytesG1(data []byte, index int, E *FP256BN.ECP) int { length := 2*FieldBytes + 1 E.ToBytes(data[index : index+length]) diff --git a/vendor/github.com/hyperledger/fabric/idemix/weak-bb.go b/vendor/github.com/hyperledger/fabric/idemix/weak-bb.go new file mode 100644 index 000000000..7b9abc638 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric/idemix/weak-bb.go @@ -0,0 +1,41 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package idemix + +import ( + "github.com/hyperledger/fabric-amcl/amcl" + "github.com/hyperledger/fabric-amcl/amcl/FP256BN" + "github.com/pkg/errors" +) + +// WBBKeyGen creates a fresh weak-Boneh-Boyen signature key pair (http://ia.cr/2004/171) +func WBBKeyGen(rng *amcl.RAND) (*FP256BN.BIG, *FP256BN.ECP2) { + sk := RandModOrder(rng) + pk := GenG2.Mul(sk) + return sk, pk +} + +// WBBSign places a weak Boneh-Boyen signature on message m using secret key sk +func WBBSign(sk *FP256BN.BIG, m *FP256BN.BIG) *FP256BN.ECP { + exp := Modadd(sk, m, GroupOrder) + exp.Invmodp(GroupOrder) + sig := GenG1.Mul(exp) + + return sig +} + +// WBBVerify verifies a weak Boneh-Boyen signature sig on message m with public key pk +func WBBVerify(pk *FP256BN.ECP2, sig *FP256BN.ECP, m *FP256BN.BIG) error { + P := FP256BN.NewECP2() + P.Copy(pk) + P.Add(GenG2.Mul(m)) // P = pk * g2^m + P.Affine() + if !FP256BN.Fexp(FP256BN.Ate(P, sig)).Equals(GenGT) { + return errors.Errorf("Weak-BB signature is invalid") + } + return nil +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 559abef56..184e108d0 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -394,10 +394,10 @@ "revisionTime": "2017-05-12T16:44:56Z" }, { - "checksumSHA1": "dl54oSjaz9RtbrkiBS71/iT4T/c=", + "checksumSHA1": "bzFbMfsRA82I8THHKIKIRMJbpBU=", "path": "github.com/hyperledger/fabric/idemix", - "revision": "968d12b56407083920cd074a973b35927c0cbde2", - "revisionTime": "2018-04-09T17:21:38Z" + "revision": "21d6a802db121026ae626462cc2f8b5613cd1ae8", + "revisionTime": "2018-04-27T20:09:32Z" }, { "checksumSHA1": "40vJyUB4ezQSn/NSadsKEOrudMc=",