github.com/yimialmonte/fabric@v2.1.1+incompatible/bccsp/idemix/bridge/credential.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  package bridge
     7  
     8  import (
     9  	"bytes"
    10  
    11  	"github.com/golang/protobuf/proto"
    12  	"github.com/hyperledger/fabric-amcl/amcl"
    13  	"github.com/hyperledger/fabric-amcl/amcl/FP256BN"
    14  	"github.com/hyperledger/fabric/bccsp"
    15  	"github.com/hyperledger/fabric/bccsp/idemix/handlers"
    16  	cryptolib "github.com/hyperledger/fabric/idemix"
    17  	"github.com/pkg/errors"
    18  )
    19  
    20  // Credential encapsulates the idemix algorithms to produce (sign) a credential
    21  // and verify it. Recall that a credential is produced by the Issuer upon a credential request,
    22  // and it is verified by the requester.
    23  type Credential struct {
    24  	NewRand func() *amcl.RAND
    25  }
    26  
    27  // Sign produces an idemix credential. It takes in input the issuer secret key,
    28  // a serialised  credential request, and a list of attribute values.
    29  // Notice that attributes should not contain attributes whose type is IdemixHiddenAttribute
    30  // cause the credential needs to carry all the attribute values.
    31  func (c *Credential) Sign(key handlers.IssuerSecretKey, credentialRequest []byte, attributes []bccsp.IdemixAttribute) (res []byte, err error) {
    32  	defer func() {
    33  		if r := recover(); r != nil {
    34  			res = nil
    35  			err = errors.Errorf("failure [%s]", r)
    36  		}
    37  	}()
    38  
    39  	iisk, ok := key.(*IssuerSecretKey)
    40  	if !ok {
    41  		return nil, errors.Errorf("invalid issuer secret key, expected *Big, got [%T]", key)
    42  	}
    43  
    44  	cr := &cryptolib.CredRequest{}
    45  	err = proto.Unmarshal(credentialRequest, cr)
    46  	if err != nil {
    47  		return nil, errors.Wrap(err, "failed unmarshalling credential request")
    48  	}
    49  
    50  	attrValues := make([]*FP256BN.BIG, len(attributes))
    51  	for i := 0; i < len(attributes); i++ {
    52  		switch attributes[i].Type {
    53  		case bccsp.IdemixBytesAttribute:
    54  			attrValues[i] = cryptolib.HashModOrder(attributes[i].Value.([]byte))
    55  		case bccsp.IdemixIntAttribute:
    56  			attrValues[i] = FP256BN.NewBIGint(attributes[i].Value.(int))
    57  		default:
    58  			return nil, errors.Errorf("attribute type not allowed or supported [%v] at position [%d]", attributes[i].Type, i)
    59  		}
    60  	}
    61  
    62  	cred, err := cryptolib.NewCredential(iisk.SK, cr, attrValues, c.NewRand())
    63  	if err != nil {
    64  		return nil, errors.WithMessage(err, "failed creating new credential")
    65  	}
    66  
    67  	return proto.Marshal(cred)
    68  }
    69  
    70  // Verify checks that an idemix credential is cryptographically correct. It takes
    71  // in input the user secret key (sk), the issuer public key (ipk), the serialised credential (credential),
    72  // and a list of attributes. The list of attributes is optional, in case it is specified, Verify
    73  // checks that the credential carries the specified attributes.
    74  func (*Credential) Verify(sk handlers.Big, ipk handlers.IssuerPublicKey, credential []byte, attributes []bccsp.IdemixAttribute) (err error) {
    75  	defer func() {
    76  		if r := recover(); r != nil {
    77  			err = errors.Errorf("failure [%s]", r)
    78  		}
    79  	}()
    80  
    81  	isk, ok := sk.(*Big)
    82  	if !ok {
    83  		return errors.Errorf("invalid user secret key, expected *Big, got [%T]", sk)
    84  	}
    85  	iipk, ok := ipk.(*IssuerPublicKey)
    86  	if !ok {
    87  		return errors.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", sk)
    88  	}
    89  
    90  	cred := &cryptolib.Credential{}
    91  	err = proto.Unmarshal(credential, cred)
    92  	if err != nil {
    93  		return err
    94  	}
    95  
    96  	for i := 0; i < len(attributes); i++ {
    97  		switch attributes[i].Type {
    98  		case bccsp.IdemixBytesAttribute:
    99  			if !bytes.Equal(
   100  				cryptolib.BigToBytes(cryptolib.HashModOrder(attributes[i].Value.([]byte))),
   101  				cred.Attrs[i]) {
   102  				return errors.Errorf("credential does not contain the correct attribute value at position [%d]", i)
   103  			}
   104  		case bccsp.IdemixIntAttribute:
   105  			if !bytes.Equal(
   106  				cryptolib.BigToBytes(FP256BN.NewBIGint(attributes[i].Value.(int))),
   107  				cred.Attrs[i]) {
   108  				return errors.Errorf("credential does not contain the correct attribute value at position [%d]", i)
   109  			}
   110  		case bccsp.IdemixHiddenAttribute:
   111  			continue
   112  		default:
   113  			return errors.Errorf("attribute type not allowed or supported [%v] at position [%d]", attributes[i].Type, i)
   114  		}
   115  	}
   116  
   117  	return cred.Ver(isk.E, iipk.PK)
   118  }