github.com/true-sqn/fabric@v2.1.1+incompatible/idemix/credrequest.go (about)

     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  	"github.com/hyperledger/fabric-amcl/amcl"
    11  	"github.com/hyperledger/fabric-amcl/amcl/FP256BN"
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  // credRequestLabel is the label used in zero-knowledge proof (ZKP) to identify that this ZKP is a credential request
    16  const credRequestLabel = "credRequest"
    17  
    18  // Credential issuance is an interactive protocol between a user and an issuer
    19  // The issuer takes its secret and public keys and user attribute values as input
    20  // The user takes the issuer public key and user secret as input
    21  // The issuance protocol consists of the following steps:
    22  // 1) The issuer sends a random nonce to the user
    23  // 2) The user creates a Credential Request using the public key of the issuer, user secret, and the nonce as input
    24  //    The request consists of a commitment to the user secret (can be seen as a public key) and a zero-knowledge proof
    25  //     of knowledge of the user secret key
    26  //    The user sends the credential request to the issuer
    27  // 3) The issuer verifies the credential request by verifying the zero-knowledge proof
    28  //    If the request is valid, the issuer issues a credential to the user by signing the commitment to the secret key
    29  //    together with the attribute values and sends the credential back to the user
    30  // 4) The user verifies the issuer's signature and stores the credential that consists of
    31  //    the signature value, a randomness used to create the signature, the user secret, and the attribute values
    32  
    33  // NewCredRequest creates a new Credential Request, the first message of the interactive credential issuance protocol
    34  // (from user to issuer)
    35  func NewCredRequest(sk *FP256BN.BIG, IssuerNonce []byte, ipk *IssuerPublicKey, rng *amcl.RAND) *CredRequest {
    36  	// Set Nym as h_{sk}^{sk}
    37  	HSk := EcpFromProto(ipk.HSk)
    38  	Nym := HSk.Mul(sk)
    39  
    40  	// generate a zero-knowledge proof of knowledge (ZK PoK) of the secret key
    41  
    42  	// Sample the randomness needed for the proof
    43  	rSk := RandModOrder(rng)
    44  
    45  	// Step 1: First message (t-values)
    46  	t := HSk.Mul(rSk) // t = h_{sk}^{r_{sk}}, cover Nym
    47  
    48  	// Step 2: Compute the Fiat-Shamir hash, forming the challenge of the ZKP.
    49  	// proofData is the data being hashed, it consists of:
    50  	// the credential request label
    51  	// 3 elements of G1 each taking 2*FieldBytes+1 bytes
    52  	// hash of the issuer public key of length FieldBytes
    53  	// issuer nonce of length FieldBytes
    54  	proofData := make([]byte, len([]byte(credRequestLabel))+3*(2*FieldBytes+1)+2*FieldBytes)
    55  	index := 0
    56  	index = appendBytesString(proofData, index, credRequestLabel)
    57  	index = appendBytesG1(proofData, index, t)
    58  	index = appendBytesG1(proofData, index, HSk)
    59  	index = appendBytesG1(proofData, index, Nym)
    60  	index = appendBytes(proofData, index, IssuerNonce)
    61  	copy(proofData[index:], ipk.Hash)
    62  	proofC := HashModOrder(proofData)
    63  
    64  	// Step 3: reply to the challenge message (s-values)
    65  	proofS := Modadd(FP256BN.Modmul(proofC, sk, GroupOrder), rSk, GroupOrder) // s = r_{sk} + C \cdot sk
    66  
    67  	// Done
    68  	return &CredRequest{
    69  		Nym:         EcpToProto(Nym),
    70  		IssuerNonce: IssuerNonce,
    71  		ProofC:      BigToBytes(proofC),
    72  		ProofS:      BigToBytes(proofS)}
    73  }
    74  
    75  // Check cryptographically verifies the credential request
    76  func (m *CredRequest) Check(ipk *IssuerPublicKey) error {
    77  	Nym := EcpFromProto(m.GetNym())
    78  	IssuerNonce := m.GetIssuerNonce()
    79  	ProofC := FP256BN.FromBytes(m.GetProofC())
    80  	ProofS := FP256BN.FromBytes(m.GetProofS())
    81  
    82  	HSk := EcpFromProto(ipk.HSk)
    83  
    84  	if Nym == nil || IssuerNonce == nil || ProofC == nil || ProofS == nil {
    85  		return errors.Errorf("one of the proof values is undefined")
    86  	}
    87  
    88  	// Verify Proof
    89  
    90  	// Recompute t-values using s-values
    91  	t := HSk.Mul(ProofS)
    92  	t.Sub(Nym.Mul(ProofC)) // t = h_{sk}^s / Nym^C
    93  
    94  	// Recompute challenge
    95  	proofData := make([]byte, len([]byte(credRequestLabel))+3*(2*FieldBytes+1)+2*FieldBytes)
    96  	index := 0
    97  	index = appendBytesString(proofData, index, credRequestLabel)
    98  	index = appendBytesG1(proofData, index, t)
    99  	index = appendBytesG1(proofData, index, HSk)
   100  	index = appendBytesG1(proofData, index, Nym)
   101  	index = appendBytes(proofData, index, IssuerNonce)
   102  	copy(proofData[index:], ipk.Hash)
   103  
   104  	if *ProofC != *HashModOrder(proofData) {
   105  		return errors.Errorf("zero knowledge proof is invalid")
   106  	}
   107  
   108  	return nil
   109  }