-
Notifications
You must be signed in to change notification settings - Fork 30
/
batch.go
159 lines (126 loc) Β· 4.1 KB
/
batch.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package schnorrkel
import (
"errors"
"github.com/gtank/merlin"
r255 "github.com/gtank/ristretto255"
)
// VerifyBatch batch verifies the given signatures
func VerifyBatch(transcripts []*merlin.Transcript, signatures []*Signature, pubkeys []*PublicKey) (bool, error) {
if len(transcripts) != len(signatures) || len(signatures) != len(pubkeys) || len(pubkeys) != len(transcripts) {
return false, errors.New("the number of transcripts, signatures, and public keys must be equal")
}
if len(transcripts) == 0 {
return true, nil
}
var err error
zero := r255.NewElement().Zero()
zs := make([]*r255.Scalar, len(transcripts))
for i := range zs {
zs[i], err = NewRandomScalar()
if err != nil {
return false, err
}
}
// compute H(R_i || P_i || m_i)
hs := make([]*r255.Scalar, len(transcripts))
s := make([]r255.Scalar, len(transcripts))
for i, t := range transcripts {
if t == nil {
return false, errors.New("transcript provided was nil")
}
t.AppendMessage([]byte("proto-name"), []byte("Schnorr-sig"))
pubc := pubkeys[i].Encode()
t.AppendMessage([]byte("sign:pk"), pubc[:])
t.AppendMessage([]byte("sign:R"), signatures[i].r.Encode([]byte{}))
h := t.ExtractBytes([]byte("sign:c"), 64)
s[i] = *r255.NewScalar()
hs[i] = &s[i]
hs[i].FromUniformBytes(h)
}
// compute β z_i P_i H(R_i || P_i || m_i)
ps := make([]*r255.Element, len(pubkeys))
for i, p := range pubkeys {
if p == nil {
return false, errors.New("public key provided was nil")
}
ps[i] = r255.NewElement().ScalarMult(zs[i], p.key)
}
phs := r255.NewElement().VarTimeMultiScalarMult(hs, ps)
// compute β z_i s_i and β z_i R_i
ss := r255.NewScalar()
rs := r255.NewElement()
for i, s := range signatures {
if s == nil {
return false, errors.New("signature provided was nil")
}
zsi := r255.NewScalar().Multiply(s.s, zs[i])
ss = r255.NewScalar().Add(ss, zsi)
zri := r255.NewElement().ScalarMult(zs[i], s.r)
rs = r255.NewElement().Add(rs, zri)
}
// β z_i P_i H(R_i || P_i || m_i) + β R_i
z := r255.NewElement().Add(phs, rs)
// B β z_i s_i
sb := r255.NewElement().ScalarBaseMult(ss)
// check -B β z_i s_i + β z_i P_i H(R_i || P_i || m_i) + β z_i R_i = 0
sb_neg := r255.NewElement().Negate(sb)
res := r255.NewElement().Add(sb_neg, z)
return res.Equal(zero) == 1, nil
}
type BatchVerifier struct {
hs []*r255.Scalar // transcript scalar
ss *r255.Scalar // sum of signature.S: β z_i s_i
rs *r255.Element // sum of signature.R: β z_i R_i
pubkeys []*r255.Element // z_i P_i
}
func NewBatchVerifier() *BatchVerifier {
return &BatchVerifier{
hs: []*r255.Scalar{},
ss: r255.NewScalar(),
rs: r255.NewElement(),
pubkeys: []*r255.Element{},
}
}
func (v *BatchVerifier) Add(t *merlin.Transcript, sig *Signature, pubkey *PublicKey) error {
if t == nil {
return errors.New("provided transcript is nil")
}
if sig == nil {
return errors.New("provided signature is nil")
}
if pubkey == nil {
return errors.New("provided public key is nil")
}
z, err := NewRandomScalar()
if err != nil {
return err
}
t.AppendMessage([]byte("proto-name"), []byte("Schnorr-sig"))
pubc := pubkey.Encode()
t.AppendMessage([]byte("sign:pk"), pubc[:])
t.AppendMessage([]byte("sign:R"), sig.r.Encode([]byte{}))
h := t.ExtractBytes([]byte("sign:c"), 64)
s := r255.NewScalar()
s.FromUniformBytes(h)
v.hs = append(v.hs, s)
zs := r255.NewScalar().Multiply(z, sig.s)
v.ss.Add(v.ss, zs)
zr := r255.NewElement().ScalarMult(z, sig.r)
v.rs.Add(v.rs, zr)
p := r255.NewElement().ScalarMult(z, pubkey.key)
v.pubkeys = append(v.pubkeys, p)
return nil
}
func (v *BatchVerifier) Verify() bool {
zero := r255.NewElement().Zero()
// compute β z_i P_i H(R_i || P_i || m_i)
phs := r255.NewElement().VarTimeMultiScalarMult(v.hs, v.pubkeys)
// β z_i P_i H(R_i || P_i || m_i) + β z_i R_i
z := r255.NewElement().Add(phs, v.rs)
// B β z_i s_i
sb := r255.NewElement().ScalarBaseMult(v.ss)
// check -B β z_i s_i + β z_i P_i H(R_i || P_i || m_i) + β z_i R_i = 0
sb_neg := r255.NewElement().Negate(sb)
res := r255.NewElement().Add(sb_neg, z)
return res.Equal(zero) == 1
}