Skip to content

Commit e8b284a

Browse files
committed
[FAB-9695] Idemix Credential Request Signer/Verifier
This change-set does the following: - implement the credential request signer/verifier - tests Change-Id: I7b6e360babced2da824cc1abfa13ed8ba97854c8 Signed-off-by: Angelo De Caro <adc@zurich.ibm.com>
1 parent be90d3c commit e8b284a

File tree

6 files changed

+502
-0
lines changed

6 files changed

+502
-0
lines changed

bccsp/idemix/cred.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
package idemix
7+
8+
import (
9+
"github.com/hyperledger/fabric/bccsp"
10+
"github.com/pkg/errors"
11+
)
12+
13+
// CredentialRequestSigner produces credential requests
14+
type CredentialRequestSigner struct {
15+
// CredRequest implements the underlying cryptographic algorithms
16+
CredRequest CredRequest
17+
}
18+
19+
func (c *CredentialRequestSigner) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte, error) {
20+
userSecretKey, ok := k.(*userSecretKey)
21+
if !ok {
22+
return nil, errors.New("invalid key, expected *userSecretKey")
23+
}
24+
credentialRequestSignerOpts, ok := opts.(*bccsp.IdemixCredentialRequestSignerOpts)
25+
if !ok {
26+
return nil, errors.New("invalid options, expected *IdemixCredentialRequestSignerOpts")
27+
}
28+
if credentialRequestSignerOpts.IssuerPK == nil {
29+
return nil, errors.New("invalid options, missing issuer public key")
30+
}
31+
issuerPK, ok := credentialRequestSignerOpts.IssuerPK.(*issuerPublicKey)
32+
if !ok {
33+
return nil, errors.New("invalid options, expected IssuerPK as *issuerPublicKey")
34+
}
35+
if len(digest) != 0 {
36+
return nil, errors.New("invalid digest, it must be empty")
37+
}
38+
39+
return c.CredRequest.Sign(userSecretKey.sk, issuerPK.pk)
40+
}
41+
42+
// CredentialRequestVerifier verifies credential requests
43+
type CredentialRequestVerifier struct {
44+
// CredRequest implements the underlying cryptographic algorithms
45+
CredRequest CredRequest
46+
}
47+
48+
func (c *CredentialRequestVerifier) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (bool, error) {
49+
issuerPublicKey, ok := k.(*issuerPublicKey)
50+
if !ok {
51+
return false, errors.New("invalid key, expected *issuerPublicKey")
52+
}
53+
if len(digest) != 0 {
54+
return false, errors.New("invalid digest, it must be empty")
55+
}
56+
57+
err := c.CredRequest.Verify(signature, issuerPublicKey.pk)
58+
if err != nil {
59+
return false, err
60+
}
61+
62+
return true, nil
63+
}

bccsp/idemix/cred_test.go

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
package idemix_test
7+
8+
import (
9+
"github.com/hyperledger/fabric/bccsp"
10+
"github.com/hyperledger/fabric/bccsp/idemix"
11+
"github.com/hyperledger/fabric/bccsp/idemix/mock"
12+
. "github.com/onsi/ginkgo"
13+
. "github.com/onsi/gomega"
14+
"github.com/pkg/errors"
15+
)
16+
17+
var _ = Describe("Credential Request", func() {
18+
19+
Describe("when creating a credential request", func() {
20+
21+
var (
22+
CredentialRequestSigner *idemix.CredentialRequestSigner
23+
fakeCredRequest *mock.CredRequest
24+
)
25+
26+
BeforeEach(func() {
27+
fakeCredRequest = &mock.CredRequest{}
28+
CredentialRequestSigner = &idemix.CredentialRequestSigner{CredRequest: fakeCredRequest}
29+
})
30+
31+
Context("and the underlying cryptographic algorithm succeed", func() {
32+
var (
33+
fakeSignature []byte
34+
)
35+
BeforeEach(func() {
36+
fakeSignature = []byte("fake signature")
37+
fakeCredRequest.SignReturns(fakeSignature, nil)
38+
})
39+
40+
It("returns no error and a signature", func() {
41+
signature, err := CredentialRequestSigner.Sign(
42+
idemix.NewUserSecretKey(nil, false),
43+
nil,
44+
&bccsp.IdemixCredentialRequestSignerOpts{IssuerPK: idemix.NewIssuerPublicKey(nil)},
45+
)
46+
Expect(err).NotTo(HaveOccurred())
47+
Expect(signature).To(BeEquivalentTo(fakeSignature))
48+
49+
})
50+
})
51+
52+
Context("and the underlying cryptographic algorithm fails", func() {
53+
BeforeEach(func() {
54+
fakeCredRequest.SignReturns(nil, errors.New("sign error"))
55+
})
56+
57+
It("returns an error", func() {
58+
signature, err := CredentialRequestSigner.Sign(
59+
idemix.NewUserSecretKey(nil, false),
60+
nil,
61+
&bccsp.IdemixCredentialRequestSignerOpts{IssuerPK: idemix.NewIssuerPublicKey(nil)},
62+
)
63+
Expect(err).To(MatchError("sign error"))
64+
Expect(signature).To(BeNil())
65+
})
66+
})
67+
68+
Context("and the options are not well formed", func() {
69+
70+
Context("and the user secret key is nil", func() {
71+
It("returns error", func() {
72+
signature, err := CredentialRequestSigner.Sign(
73+
nil,
74+
nil,
75+
&bccsp.IdemixCredentialRequestSignerOpts{IssuerPK: idemix.NewIssuerPublicKey(nil)},
76+
)
77+
Expect(err).To(MatchError("invalid key, expected *userSecretKey"))
78+
Expect(signature).To(BeNil())
79+
})
80+
})
81+
82+
Context("and the user secret key is not of type *userSecretKey", func() {
83+
It("returns error", func() {
84+
signature, err := CredentialRequestSigner.Sign(
85+
idemix.NewIssuerPublicKey(nil),
86+
nil,
87+
&bccsp.IdemixCredentialRequestSignerOpts{IssuerPK: idemix.NewIssuerPublicKey(nil)},
88+
)
89+
Expect(err).To(MatchError("invalid key, expected *userSecretKey"))
90+
Expect(signature).To(BeNil())
91+
})
92+
})
93+
94+
Context("and the option is missing", func() {
95+
It("returns error", func() {
96+
signature, err := CredentialRequestSigner.Sign(
97+
idemix.NewUserSecretKey(nil, false),
98+
nil,
99+
nil,
100+
)
101+
Expect(err).To(MatchError("invalid options, expected *IdemixCredentialRequestSignerOpts"))
102+
Expect(signature).To(BeNil())
103+
})
104+
})
105+
106+
Context("and the option is not of type *bccsp.IdemixCredentialRequestSignerOpts", func() {
107+
It("returns error", func() {
108+
signature, err := CredentialRequestSigner.Sign(
109+
idemix.NewUserSecretKey(nil, false),
110+
nil,
111+
&bccsp.IdemixSignerOpts{},
112+
)
113+
Expect(err).To(MatchError("invalid options, expected *IdemixCredentialRequestSignerOpts"))
114+
Expect(signature).To(BeNil())
115+
})
116+
})
117+
118+
Context("and the issuer public key is missing", func() {
119+
It("returns error", func() {
120+
signature, err := CredentialRequestSigner.Sign(
121+
idemix.NewUserSecretKey(nil, false),
122+
nil,
123+
&bccsp.IdemixCredentialRequestSignerOpts{IssuerPK: nil},
124+
)
125+
Expect(err).To(MatchError("invalid options, missing issuer public key"))
126+
Expect(signature).To(BeNil())
127+
})
128+
})
129+
130+
Context("and the issuer public key is not of type *issuerPublicKey", func() {
131+
It("returns error", func() {
132+
signature, err := CredentialRequestSigner.Sign(
133+
idemix.NewUserSecretKey(nil, false),
134+
nil,
135+
&bccsp.IdemixCredentialRequestSignerOpts{IssuerPK: idemix.NewUserSecretKey(nil, false)},
136+
)
137+
Expect(err).To(MatchError("invalid options, expected IssuerPK as *issuerPublicKey"))
138+
Expect(signature).To(BeNil())
139+
})
140+
})
141+
142+
Context("and the digest is not nil", func() {
143+
It("returns error", func() {
144+
signature, err := CredentialRequestSigner.Sign(
145+
idemix.NewUserSecretKey(nil, false),
146+
[]byte{1, 2, 3, 4},
147+
&bccsp.IdemixCredentialRequestSignerOpts{IssuerPK: idemix.NewIssuerPublicKey(nil)},
148+
)
149+
Expect(err).To(MatchError("invalid digest, it must be empty"))
150+
Expect(signature).To(BeNil())
151+
})
152+
})
153+
154+
})
155+
})
156+
157+
Describe("when verifying a credential request", func() {
158+
159+
var (
160+
CredentialRequestVerifier *idemix.CredentialRequestVerifier
161+
fakeCredRequest *mock.CredRequest
162+
)
163+
164+
BeforeEach(func() {
165+
fakeCredRequest = &mock.CredRequest{}
166+
CredentialRequestVerifier = &idemix.CredentialRequestVerifier{CredRequest: fakeCredRequest}
167+
})
168+
169+
Context("and the underlying cryptographic algorithm succeed", func() {
170+
BeforeEach(func() {
171+
fakeCredRequest.VerifyReturns(nil)
172+
})
173+
174+
It("returns no error and valid signature", func() {
175+
valid, err := CredentialRequestVerifier.Verify(
176+
idemix.NewIssuerPublicKey(nil),
177+
[]byte("fake signature"),
178+
nil,
179+
nil,
180+
)
181+
Expect(err).NotTo(HaveOccurred())
182+
Expect(valid).To(BeTrue())
183+
})
184+
})
185+
186+
Context("and the underlying cryptographic algorithm fails", func() {
187+
BeforeEach(func() {
188+
fakeCredRequest.VerifyReturns(errors.New("verify error"))
189+
})
190+
191+
It("returns an error", func() {
192+
valid, err := CredentialRequestVerifier.Verify(
193+
idemix.NewIssuerPublicKey(nil),
194+
[]byte("fake signature"),
195+
nil,
196+
nil,
197+
)
198+
Expect(err).To(MatchError("verify error"))
199+
Expect(valid).To(BeFalse())
200+
})
201+
})
202+
203+
Context("and the parameters are not well formed", func() {
204+
205+
Context("and the issuer public key is nil", func() {
206+
It("returns error", func() {
207+
valid, err := CredentialRequestVerifier.Verify(
208+
nil,
209+
[]byte("fake signature"),
210+
nil,
211+
nil,
212+
)
213+
Expect(err).To(MatchError("invalid key, expected *issuerPublicKey"))
214+
Expect(valid).To(BeFalse())
215+
})
216+
})
217+
218+
Context("and the issuer public key is not of type *issuerPublicKey", func() {
219+
It("returns error", func() {
220+
valid, err := CredentialRequestVerifier.Verify(
221+
idemix.NewUserSecretKey(nil, false),
222+
[]byte("fake signature"),
223+
nil,
224+
nil,
225+
)
226+
Expect(err).To(MatchError("invalid key, expected *issuerPublicKey"))
227+
Expect(valid).To(BeFalse())
228+
})
229+
})
230+
231+
Context("and the digest is not nil", func() {
232+
It("returns error", func() {
233+
valid, err := CredentialRequestVerifier.Verify(
234+
idemix.NewIssuerPublicKey(nil),
235+
[]byte("fake signature"),
236+
[]byte{1, 2, 3, 4},
237+
nil,
238+
)
239+
Expect(err).To(MatchError("invalid digest, it must be empty"))
240+
Expect(valid).To(BeFalse())
241+
})
242+
})
243+
244+
})
245+
})
246+
})

bccsp/idemix/idemix.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,14 @@ type User interface {
4848
// MakeNym creates a new unlinkable pseudonym
4949
MakeNym(sk Big, key IssuerPublicKey) (Ecp, Big, error)
5050
}
51+
52+
// CredRequest is a local interface to decouple from the idemix implementation
53+
// of the issuance of credential requests.
54+
type CredRequest interface {
55+
// Sign creates a new Credential Request, the first message of the interactive credential issuance protocol
56+
// (from user to issuer)
57+
Sign(sk Big, ipk IssuerPublicKey) ([]byte, error)
58+
59+
// Verify verifies the credential request
60+
Verify(credRequest []byte, ipk IssuerPublicKey) error
61+
}

bccsp/idemix/idemix_suite_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
//go:generate counterfeiter -o mock/user.go -fake-name User . User
1919
//go:generate counterfeiter -o mock/big.go -fake-name Big . Big
2020
//go:generate counterfeiter -o mock/ecp.go -fake-name Ecp . Ecp
21+
//go:generate counterfeiter -o mock/credrequest.go -fake-name CredRequest . CredRequest
2122

2223
func TestPlain(t *testing.T) {
2324
RegisterFailHandler(Fail)

0 commit comments

Comments
 (0)