github.com/kaituanwang/hyperledger@v2.0.1+incompatible/idemix/nymsignature.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  // NewSignature creates a new idemix pseudonym signature
    16  func NewNymSignature(sk *FP256BN.BIG, Nym *FP256BN.ECP, RNym *FP256BN.BIG, ipk *IssuerPublicKey, msg []byte, rng *amcl.RAND) (*NymSignature, error) {
    17  	// Validate inputs
    18  	if sk == nil || Nym == nil || RNym == nil || ipk == nil || rng == nil {
    19  		return nil, errors.Errorf("cannot create NymSignature: received nil input")
    20  	}
    21  
    22  	Nonce := RandModOrder(rng)
    23  
    24  	HRand := EcpFromProto(ipk.HRand)
    25  	HSk := EcpFromProto(ipk.HSk)
    26  
    27  	// The rest of this function constructs the non-interactive zero knowledge proof proving that
    28  	// the signer 'owns' this pseudonym, i.e., it knows the secret key and randomness on which it is based.
    29  	// Recall that (Nym,RNym) is the output of MakeNym. Therefore, Nym = h_{sk}^sk \cdot h_r^r
    30  
    31  	// Sample the randomness needed for the proof
    32  	rSk := RandModOrder(rng)
    33  	rRNym := RandModOrder(rng)
    34  
    35  	// Step 1: First message (t-values)
    36  	t := HSk.Mul2(rSk, HRand, rRNym) // t = h_{sk}^{r_sk} \cdot h_r^{r_{RNym}
    37  
    38  	// Step 2: Compute the Fiat-Shamir hash, forming the challenge of the ZKP.
    39  	// proofData will hold the data being hashed, it consists of:
    40  	// - the signature label
    41  	// - 2 elements of G1 each taking 2*FieldBytes+1 bytes
    42  	// - one bigint (hash of the issuer public key) of length FieldBytes
    43  	// - disclosed attributes
    44  	// - message being signed
    45  	proofData := make([]byte, len([]byte(signLabel))+2*(2*FieldBytes+1)+FieldBytes+len(msg))
    46  	index := 0
    47  	index = appendBytesString(proofData, index, signLabel)
    48  	index = appendBytesG1(proofData, index, t)
    49  	index = appendBytesG1(proofData, index, Nym)
    50  	copy(proofData[index:], ipk.Hash)
    51  	index = index + FieldBytes
    52  	copy(proofData[index:], msg)
    53  	c := HashModOrder(proofData)
    54  	// combine the previous hash and the nonce and hash again to compute the final Fiat-Shamir value 'ProofC'
    55  	index = 0
    56  	proofData = proofData[:2*FieldBytes]
    57  	index = appendBytesBig(proofData, index, c)
    58  	index = appendBytesBig(proofData, index, Nonce)
    59  	ProofC := HashModOrder(proofData)
    60  
    61  	// Step 3: reply to the challenge message (s-values)
    62  	ProofSSk := Modadd(rSk, FP256BN.Modmul(ProofC, sk, GroupOrder), GroupOrder)       // s_{sk} = r_{sk} + C \cdot sk
    63  	ProofSRNym := Modadd(rRNym, FP256BN.Modmul(ProofC, RNym, GroupOrder), GroupOrder) // s_{RNym} = r_{RNym} + C \cdot RNym
    64  
    65  	// The signature consists of the Fiat-Shamir hash (ProofC), the s-values (ProofSSk, ProofSRNym), and the nonce.
    66  	return &NymSignature{
    67  		ProofC:     BigToBytes(ProofC),
    68  		ProofSSk:   BigToBytes(ProofSSk),
    69  		ProofSRNym: BigToBytes(ProofSRNym),
    70  		Nonce:      BigToBytes(Nonce)}, nil
    71  }
    72  
    73  // Ver verifies an idemix NymSignature
    74  func (sig *NymSignature) Ver(nym *FP256BN.ECP, ipk *IssuerPublicKey, msg []byte) error {
    75  	ProofC := FP256BN.FromBytes(sig.GetProofC())
    76  	ProofSSk := FP256BN.FromBytes(sig.GetProofSSk())
    77  	ProofSRNym := FP256BN.FromBytes(sig.GetProofSRNym())
    78  	Nonce := FP256BN.FromBytes(sig.GetNonce())
    79  
    80  	HRand := EcpFromProto(ipk.HRand)
    81  	HSk := EcpFromProto(ipk.HSk)
    82  
    83  	// Verify Proof
    84  
    85  	// Recompute t-values using s-values
    86  	t := HSk.Mul2(ProofSSk, HRand, ProofSRNym)
    87  	t.Sub(nym.Mul(ProofC)) // t = h_{sk}^{s_{sk} \ cdot h_r^{s_{RNym}
    88  
    89  	// Recompute challenge
    90  	proofData := make([]byte, len([]byte(signLabel))+2*(2*FieldBytes+1)+FieldBytes+len(msg))
    91  	index := 0
    92  	index = appendBytesString(proofData, index, signLabel)
    93  	index = appendBytesG1(proofData, index, t)
    94  	index = appendBytesG1(proofData, index, nym)
    95  	copy(proofData[index:], ipk.Hash)
    96  	index = index + FieldBytes
    97  	copy(proofData[index:], msg)
    98  	c := HashModOrder(proofData)
    99  	index = 0
   100  	proofData = proofData[:2*FieldBytes]
   101  	index = appendBytesBig(proofData, index, c)
   102  	index = appendBytesBig(proofData, index, Nonce)
   103  
   104  	if *ProofC != *HashModOrder(proofData) {
   105  		return errors.Errorf("pseudonym signature invalid: zero-knowledge proof is invalid")
   106  	}
   107  
   108  	return nil
   109  }