This repository has been archived by the owner on Apr 9, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 10
/
nymsignature.go
109 lines (90 loc) · 3.94 KB
/
nymsignature.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
102
103
104
105
106
107
108
109
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package idemix
import (
"github.com/hyperledger/fabric-amcl/amcl"
"github.com/hyperledger/fabric-amcl/amcl/FP256BN"
"github.com/pkg/errors"
)
// NewSignature creates a new idemix pseudonym signature
func NewNymSignature(sk *FP256BN.BIG, Nym *FP256BN.ECP, RNym *FP256BN.BIG, ipk *IssuerPublicKey, msg []byte, rng *amcl.RAND) (*NymSignature, error) {
// Validate inputs
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.
// Recall that (Nym,RNym) is the output of MakeNym. Therefore, Nym = h_{sk}^sk \cdot h_r^r
// Sample the randomness needed for the proof
rSk := RandModOrder(rng)
rRNym := RandModOrder(rng)
// Step 1: First message (t-values)
t := HSk.Mul2(rSk, HRand, rRNym) // t = h_{sk}^{r_sk} \cdot h_r^{r_{RNym}
// Step 2: 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)
// Step 3: reply to the challenge message (s-values)
ProofSSk := Modadd(rSk, FP256BN.Modmul(ProofC, sk, GroupOrder), GroupOrder) // s_{sk} = r_{sk} + C \cdot sk
ProofSRNym := Modadd(rRNym, FP256BN.Modmul(ProofC, RNym, GroupOrder), GroupOrder) // s_{RNym} = r_{RNym} + C \cdot RNym
// The signature consists of the Fiat-Shamir hash (ProofC), the s-values (ProofSSk, ProofSRNym), and the nonce.
return &NymSignature{
ProofC: BigToBytes(ProofC),
ProofSSk: BigToBytes(ProofSSk),
ProofSRNym: BigToBytes(ProofSRNym),
Nonce: BigToBytes(Nonce)}, nil
}
// Ver verifies an idemix NymSignature
func (sig *NymSignature) Ver(nym *FP256BN.ECP, ipk *IssuerPublicKey, msg []byte) error {
ProofC := FP256BN.FromBytes(sig.GetProofC())
ProofSSk := FP256BN.FromBytes(sig.GetProofSSk())
ProofSRNym := FP256BN.FromBytes(sig.GetProofSRNym())
Nonce := FP256BN.FromBytes(sig.GetNonce())
HRand := EcpFromProto(ipk.HRand)
HSk := EcpFromProto(ipk.HSk)
// Verify Proof
// Recompute t-values using s-values
t := HSk.Mul2(ProofSSk, HRand, ProofSRNym)
t.Sub(nym.Mul(ProofC)) // t = h_{sk}^{s_{sk} \ cdot h_r^{s_{RNym}
// Recompute challenge
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 != *HashModOrder(proofData) {
return errors.Errorf("pseudonym signature invalid: zero-knowledge proof is invalid")
}
return nil
}