Skip to content

Commit

Permalink
Merge "[FAB-0644] cryptographic check in idemixmsp.Validate()"
Browse files Browse the repository at this point in the history
  • Loading branch information
binhn authored and Gerrit Code Review committed Oct 18, 2017
2 parents 5b38cbc + df735eb commit 7461c39
Show file tree
Hide file tree
Showing 9 changed files with 352 additions and 169 deletions.
126 changes: 89 additions & 37 deletions idemix/idemix.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions idemix/idemix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ func TestIdemix(t *testing.T) {

disclosure := []byte{0, 0, 0, 0, 0}
msg := []byte{1, 2, 3, 4, 5}
sig := NewSignature(cred, sk, Nym, RandNym, key.IPk, disclosure, msg, rng)
sig, err := NewSignature(cred, sk, Nym, RandNym, key.IPk, disclosure, msg, rng)
assert.NoError(t, err)

err = sig.Ver(disclosure, key.IPk, msg, nil)
if err != nil {
Expand All @@ -111,11 +112,22 @@ func TestIdemix(t *testing.T) {

// Test signing selective disclosure
disclosure = []byte{0, 1, 1, 1, 1}
sig = NewSignature(cred, sk, Nym, RandNym, key.IPk, disclosure, msg, rng)
sig, err = NewSignature(cred, sk, Nym, RandNym, key.IPk, disclosure, msg, rng)
assert.NoError(t, err)

err = sig.Ver(disclosure, key.IPk, msg, attrs)
if err != nil {
t.Fatalf("Signature should be valid but verification returned error: %s", err)
return
}

// Test NymSignatures
nymsig, err := NewNymSignature(sk, Nym, RandNym, key.IPk, []byte("testing"), rng)
assert.NoError(t, err)

err = nymsig.Ver(Nym, key.IPk, []byte("testing"))
if err != nil {
t.Fatalf("NymSig should be valid but verification returned error: %s", err)
return
}
}
110 changes: 110 additions & 0 deletions idemix/nymsignature.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
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"
)

// NewSignature creates a new idemix pseudonym signature
func NewNymSignature(sk *amcl.BIG, Nym *amcl.ECP, RNym *amcl.BIG, ipk *IssuerPublicKey, msg []byte, rng *amcl.RAND) (*NymSignature, error) {
if sk == nil || Nym == nil || RNym == nil || ipk == nil || rng == nil {
return nil, errors.Errorf("cannot create NymSignature: received nil input")
}

Nonce := RandModOrder(rng)

HRand := EcpFromProto(ipk.HRand)
HSk := EcpFromProto(ipk.HSk)

// The rest of this function constructs the non-interactive zero knowledge proof proving that
// the signer 'owns' this pseudonym, i.e., it knows the secret key and randomness on which it is based.

// take the randomness used to compute the commitment values (aka t-values) for the ZKP
rSk := RandModOrder(rng)
rRNym := RandModOrder(rng)

// Compute the commitment (aka t-value)
t := HSk.Mul2(rSk, HRand, rRNym)

// Next, we compute the Fiat-Shamir hash, forming the challenge of the ZKP.
// proofData will hold the data being hashed, it consists of:
// - the signature label
// - 2 elements of G1 each taking 2*FieldBytes+1 bytes
// - one bigint (hash of the issuer public key) of length FieldBytes
// - disclosed attributes
// - message being signed
proofData := make([]byte, len([]byte(signLabel))+2*(2*FieldBytes+1)+FieldBytes+len(msg))
index := 0
index = appendBytesString(proofData, index, signLabel)
index = appendBytesG1(proofData, index, t)
index = appendBytesG1(proofData, index, Nym)
copy(proofData[index:], ipk.Hash)
index = index + FieldBytes
copy(proofData[index:], msg)
c := HashModOrder(proofData)

// combine the previous hash and the nonce and hash again to compute the final Fiat-Shamir value 'ProofC'
index = 0
proofData = proofData[:2*FieldBytes]
index = appendBytesBig(proofData, index, c)
index = appendBytesBig(proofData, index, Nonce)
ProofC := HashModOrder(proofData)

// Finally, we compute the s-values, which form the response answering challenge c
ProofSSk := amcl.Modadd(rSk, amcl.Modmul(ProofC, sk, GroupOrder), GroupOrder)
ProofSRNym := amcl.Modadd(rRNym, amcl.Modmul(ProofC, RNym, GroupOrder), GroupOrder)

// The signature consists of the Fiat-Shamir hash (ProofC), the s-values (ProofSSk, ProofSRNym), and the nonce.
return &NymSignature{
BigToBytes(ProofC),
BigToBytes(ProofSSk),
BigToBytes(ProofSRNym),
BigToBytes(Nonce)}, nil
}

// Ver verifies an idemix NymSignature
func (sig *NymSignature) Ver(nym *amcl.ECP, ipk *IssuerPublicKey, msg []byte) error {
ProofC := amcl.FromBytes(sig.GetProofC())
ProofSSk := amcl.FromBytes(sig.GetProofSSk())
ProofSRNym := amcl.FromBytes(sig.GetProofSRNym())

Nonce := amcl.FromBytes(sig.GetNonce())

HRand := EcpFromProto(ipk.HRand)
HSk := EcpFromProto(ipk.HSk)

t := HSk.Mul2(ProofSSk, HRand, ProofSRNym)
t.Sub(nym.Mul(ProofC))

// proofData is the data being hashed, it consists of:
// the signature label
// 2 elements of G1 each taking 2*FieldBytes+1 bytes
// one bigint (hash of the issuer public key) of length FieldBytes
// disclosed attributes
// message being signed
proofData := make([]byte, len([]byte(signLabel))+2*(2*FieldBytes+1)+FieldBytes+len(msg))
index := 0
index = appendBytesString(proofData, index, signLabel)
index = appendBytesG1(proofData, index, t)
index = appendBytesG1(proofData, index, nym)
copy(proofData[index:], ipk.Hash)
index = index + FieldBytes
copy(proofData[index:], msg)

c := HashModOrder(proofData)
index = 0
proofData = proofData[:2*FieldBytes]
index = appendBytesBig(proofData, index, c)
index = appendBytesBig(proofData, index, Nonce)
if !ProofC.Equals(HashModOrder(proofData)) {
return errors.Errorf("pseudonym signature invalid: zero-knowledge proof is invalid")
}

return nil
}
33 changes: 19 additions & 14 deletions idemix/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ func hiddenIndices(Disclosure []byte) []int {
// The []byte Disclosure steers which attributes are disclosed:
// if Disclosure[i] == 0 then attribute i remains hidden and otherwise it is disclosed.
// We use the zero-knowledge proof by http://eprint.iacr.org/2016/663.pdf to prove knowledge of a BBS+ signature
func NewSignature(cred *Credential, sk *amcl.BIG, Nym *amcl.ECP, RNym *amcl.BIG, ipk *IssuerPublicKey, Disclosure []byte, msg []byte, rng *amcl.RAND) *Signature {
func NewSignature(cred *Credential, sk *amcl.BIG, Nym *amcl.ECP, RNym *amcl.BIG, ipk *IssuerPublicKey, Disclosure []byte, msg []byte, rng *amcl.RAND) (*Signature, error) {
if cred == nil || sk == nil || Nym == nil || RNym == nil || ipk == nil || rng == nil {
return nil, errors.Errorf("cannot create idemix signature: received nil input")
}

HiddenIndices := hiddenIndices(Disclosure)

// Start sig
Expand Down Expand Up @@ -137,19 +141,20 @@ func NewSignature(cred *Credential, sk *amcl.BIG, Nym *amcl.ECP, RNym *amcl.BIG,
}

return &Signature{
EcpToProto(APrime),
EcpToProto(ABar),
EcpToProto(BPrime),
BigToBytes(ProofC),
BigToBytes(ProofSSk),
BigToBytes(ProofSE),
BigToBytes(ProofSR2),
BigToBytes(ProofSR3),
BigToBytes(ProofSSPrime),
ProofSAttrs,
BigToBytes(Nonce),
EcpToProto(Nym),
BigToBytes(ProofSRNym)}
EcpToProto(APrime),
EcpToProto(ABar),
EcpToProto(BPrime),
BigToBytes(ProofC),
BigToBytes(ProofSSk),
BigToBytes(ProofSE),
BigToBytes(ProofSR2),
BigToBytes(ProofSR3),
BigToBytes(ProofSSPrime),
ProofSAttrs,
BigToBytes(Nonce),
EcpToProto(Nym),
BigToBytes(ProofSRNym)},
nil
}

// Ver verifies an idemix signature
Expand Down
Loading

0 comments on commit 7461c39

Please sign in to comment.