forked from hyperledger/fabric
/
credrequest.go
101 lines (84 loc) · 4.2 KB
/
credrequest.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package idemix
import (
amcl "github.com/manudrijvers/amcl/go"
"github.com/pkg/errors"
)
// credRequestLabel is the label used in zero-knowledge proof (ZKP) to identify that this ZKP is a credential request
const credRequestLabel = "credRequest"
// Credential issuance is an interactive protocol between a user and an issuer
// The issuer takes its secret and public keys and user attribute values as input
// The user takes the issuer public key and user secret as input
// The issuance protocol consists of the following steps:
// 1) The issuer sends a random nonce to the user
// 2) The user creates a Credential Request using the public key of the issuer, user secret, and the nonce as input
// The request consists of a commitment to the user secret (can be seen as a public key) and a zero-knowledge proof
// of knowledge of the user secret key
// The user sends the credential request to the issuer
// 3) The issuer verifies the credential request by verifying the zero-knowledge proof
// If the request is valid, the issuer issues a credential to the user by signing the commitment to the secret key
// together with the attribute values and sends the credential back to the user
// 4) The user verifies the issuer's signature and stores the credential that consists of
// 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 *amcl.BIG, credS1 *amcl.BIG, IssuerNonce *amcl.BIG, ipk *IssuerPublicKey, rng *amcl.RAND) *CredRequest {
HSk := EcpFromProto(ipk.HSk)
HRand := EcpFromProto(ipk.HRand)
Nym := HSk.Mul2(sk, HRand, credS1)
// Create ZK Proof
rSk := RandModOrder(rng)
rRand := RandModOrder(rng)
t := HSk.Mul2(rSk, HRand, rRand)
// proofData is the data being hashed, it consists of:
// the credential request label
// 3 elements of G1 each taking 2*FieldBytes+1 bytes
// hash of the issuer public key of length FieldBytes
// issuer nonce of length FieldBytes
proofData := make([]byte, len([]byte(credRequestLabel))+3*(2*FieldBytes+1)+2*FieldBytes)
index := 0
index = appendBytesString(proofData, index, credRequestLabel)
index = appendBytesG1(proofData, index, t)
index = appendBytesG1(proofData, index, HSk)
index = appendBytesG1(proofData, index, Nym)
index = appendBytesBig(proofData, index, IssuerNonce)
copy(proofData[index:], ipk.Hash)
proofC := HashModOrder(proofData)
proofS1 := amcl.Modadd(amcl.Modmul(proofC, sk, GroupOrder), rSk, GroupOrder)
proofS2 := amcl.Modadd(amcl.Modmul(proofC, credS1, GroupOrder), rRand, GroupOrder)
return &CredRequest{EcpToProto(Nym), BigToBytes(IssuerNonce), BigToBytes(proofC), BigToBytes(proofS1), BigToBytes(proofS2)}
}
// Check cryptographically verifies the credential request
func (m *CredRequest) Check(ipk *IssuerPublicKey) error {
Nym := EcpFromProto(m.GetNym())
IssuerNonce := amcl.FromBytes(m.GetIssuerNonce())
ProofC := amcl.FromBytes(m.GetProofC())
ProofS1 := amcl.FromBytes(m.GetProofS1())
ProofS2 := amcl.FromBytes(m.GetProofS2())
HSk := EcpFromProto(ipk.HSk)
HRand := EcpFromProto(ipk.HRand)
if Nym == nil || IssuerNonce == nil || ProofC == nil || ProofS1 == nil || ProofS2 == nil {
return errors.Errorf("one of the proof values is undefined")
}
t := HSk.Mul2(ProofS1, HRand, ProofS2)
t.Sub(Nym.Mul(ProofC))
// proofData is the data being hashed, it consists of:
// the credential request label
// 3 elements of G1 each taking 2*FieldBytes+1 bytes
// hash of the issuer public key of length FieldBytes
// issuer nonce of length FieldBytes
proofData := make([]byte, len([]byte(credRequestLabel))+3*(2*FieldBytes+1)+2*FieldBytes)
index := 0
index = appendBytesString(proofData, index, credRequestLabel)
index = appendBytesG1(proofData, index, t)
index = appendBytesG1(proofData, index, HSk)
index = appendBytesG1(proofData, index, Nym)
index = appendBytesBig(proofData, index, IssuerNonce)
copy(proofData[index:], ipk.Hash)
if !ProofC.Equals(HashModOrder(proofData)) {
return errors.Errorf("zero knowledge proof is invalid")
}
return nil
}