Skip to content

Commit 9570d47

Browse files
author
Manu Drijvers
committed
[FAB-8921] add idemix revocation authority
This commit adds the idemix revocaiton authority, which creates the 'whitelist' idemix users will use to prove that they are unrevoked. Change-Id: Ie59a06acd9a3550ae36595875b1ca71106369a05 Signed-off-by: Manu Drijvers <mdr@zurich.ibm.com>
1 parent d72c7a4 commit 9570d47

File tree

4 files changed

+240
-38
lines changed

4 files changed

+240
-38
lines changed

idemix/idemix.pb.go

+98-38
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

idemix/idemix_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,27 @@ func TestIdemix(t *testing.T) {
108108
assert.Error(t, cred.Ver(sk, key.IPk), "credential with nil attribute should be invalid")
109109
cred.Attrs = attrsBackup
110110

111+
// Generate a revocation key pair
112+
revocationKey, err := GenerateLongTermRevocationKey()
113+
assert.NoError(t, err)
114+
115+
// Create CRI that contains no revocation mechanism
116+
epoch := 0
117+
cri, err := CreateCRI(revocationKey, []*FP256BN.BIG{}, epoch, ALG_NO_REVOCATION, rng)
118+
assert.NoError(t, err)
119+
err = VerifyEpochPK(&revocationKey.PublicKey, cri.EpochPK, cri.EpochPKSig, int(cri.Epoch), RevocationAlgorithm(cri.RevocationAlg))
120+
assert.NoError(t, err)
121+
122+
// make sure that epoch pk is not valid in future epoch
123+
err = VerifyEpochPK(&revocationKey.PublicKey, cri.EpochPK, cri.EpochPKSig, int(cri.Epoch)+1, RevocationAlgorithm(cri.RevocationAlg))
124+
assert.Error(t, err)
125+
126+
// Test bad input
127+
_, err = CreateCRI(nil, []*FP256BN.BIG{}, epoch, ALG_NO_REVOCATION, rng)
128+
assert.Error(t, err)
129+
_, err = CreateCRI(revocationKey, []*FP256BN.BIG{}, epoch, ALG_NO_REVOCATION, nil)
130+
assert.Error(t, err)
131+
111132
// Test signing no disclosure
112133
Nym, RandNym := MakeNym(sk, key.IPk, rng)
113134

idemix/revocation_authority.go

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package idemix
8+
9+
import (
10+
"crypto/ecdsa"
11+
12+
"crypto/rand"
13+
"crypto/sha256"
14+
15+
"crypto/elliptic"
16+
17+
"math/big"
18+
19+
"github.com/golang/protobuf/proto"
20+
"github.com/hyperledger/fabric-amcl/amcl"
21+
"github.com/hyperledger/fabric-amcl/amcl/FP256BN"
22+
"github.com/pkg/errors"
23+
)
24+
25+
type RevocationAlgorithm int32
26+
27+
const (
28+
ALG_NO_REVOCATION RevocationAlgorithm = iota
29+
)
30+
31+
var ProofBytes = map[RevocationAlgorithm]int{
32+
ALG_NO_REVOCATION: 0,
33+
}
34+
35+
// GenerateLongTermRevocationKey generates a long term signing key that will be used for revocation
36+
func GenerateLongTermRevocationKey() (*ecdsa.PrivateKey, error) {
37+
return ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
38+
}
39+
40+
// CreateCRI creates the Credential Revocation Information for a certain time period (epoch).
41+
// Users can use the CRI to prove that they are not revoked.
42+
func CreateCRI(key *ecdsa.PrivateKey, unrevokedHandles []*FP256BN.BIG, epoch int, alg RevocationAlgorithm, rng *amcl.RAND) (*CredentialRevocationInformation, error) {
43+
if key == nil || rng == nil {
44+
return nil, errors.Errorf("CreateCRI received nil input")
45+
}
46+
cri := &CredentialRevocationInformation{}
47+
cri.RevocationAlg = int32(alg)
48+
cri.Epoch = int64(epoch)
49+
50+
if alg == ALG_NO_REVOCATION {
51+
// put a dummy PK in the proto
52+
cri.EpochPK = Ecp2ToProto(GenG2)
53+
} else {
54+
// create epoch key
55+
_, epochPk := WBBKeyGen(rng)
56+
cri.EpochPK = Ecp2ToProto(epochPk)
57+
}
58+
59+
// sign epoch + epoch key with long term key
60+
bytesToSign, err := proto.Marshal(cri)
61+
digest := sha256.New().Sum(bytesToSign)
62+
63+
pkSigR, pkSigS, err := ecdsa.Sign(rand.Reader, key, digest)
64+
if err != nil {
65+
return nil, err
66+
}
67+
cri.EpochPKSig = append(pkSigR.Bytes(), pkSigS.Bytes()...)
68+
69+
if alg == ALG_NO_REVOCATION {
70+
return cri, nil
71+
} else {
72+
return nil, errors.Errorf("the specified revocation algorithm is not supported.")
73+
}
74+
}
75+
76+
// VerifyEpochPK verifies that the revocation PK for a certain epoch is valid,
77+
// by checking that it was signed with the long term revocation key.
78+
// Note that even if we use no revocation (i.e., alg = ALG_NO_REVOCATION), we need
79+
// to verify the signature to make sure the issuer indeed signed that no revocation
80+
// is used in this epoch.
81+
func VerifyEpochPK(pk *ecdsa.PublicKey, epochPK *ECP2, epochPkSig []byte, epoch int, alg RevocationAlgorithm) error {
82+
if pk == nil || epochPK == nil {
83+
return errors.Errorf("EpochPK invalid: received nil input")
84+
}
85+
cri := &CredentialRevocationInformation{}
86+
cri.RevocationAlg = int32(alg)
87+
cri.EpochPK = epochPK
88+
cri.Epoch = int64(epoch)
89+
bytesToSign, err := proto.Marshal(cri)
90+
if err != nil {
91+
return err
92+
}
93+
digest := sha256.New().Sum(bytesToSign)
94+
sigR := &big.Int{}
95+
sigR.SetBytes(epochPkSig[0 : len(epochPkSig)/2])
96+
sigS := &big.Int{}
97+
sigS.SetBytes(epochPkSig[len(epochPkSig)/2:])
98+
99+
if !ecdsa.Verify(pk, digest, sigR, sigS) {
100+
return errors.Errorf("EpochPKSig invalid")
101+
}
102+
103+
return nil
104+
}

protos/idemix/idemix.proto

+17
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,21 @@ message NymSignature {
117117
bytes ProofSRNym = 3;
118118
// Nonce is a fresh nonce used for the signature
119119
bytes Nonce = 4;
120+
}
121+
122+
message CredentialRevocationInformation {
123+
// Epoch contains the epoch (time window) in which this CRI is valid
124+
int64 Epoch = 1;
125+
126+
// EpochPK is the public key that is used by the revocation authority in this epoch
127+
ECP2 EpochPK = 2;
128+
129+
// EpochPKSig is a signature on the EpochPK valid under the revocation authority's long term key
130+
bytes EpochPKSig = 3;
131+
132+
// RevocationAlg denotes which revocation algorithm is used
133+
int32 RevocationAlg = 4;
134+
135+
// RevocationData contains data specific to the revocation algorithm used
136+
bytes RevocationData = 5;
120137
}

0 commit comments

Comments
 (0)