go-blindsecp256k1/blindsecp256k1.go
blindsecp256k1.goRaw
1// Package blindsecp256k1 implements the Blind signature scheme explained at
2// "New Blind Signature Schemes Based on the (Elliptic Curve) Discrete
3// Logarithm Problem", by Hamid Mala & Nafiseh Nezhadansari
4// https://sci-hub.do/10.1109/ICCKE.2013.6682844
5//
6// LICENSE can be found at https://github.com/arnaucube/go-blindsecp256k1/blob/master/LICENSE
7//
8package blindsecp256k1
9
10// WARNING: WIP code
11
12import (
13 "bytes"
14 "crypto/rand"
15 "fmt"
16 "math/big"
17
18 "github.com/btcsuite/btcd/btcec"
19 "github.com/ethereum/go-ethereum/crypto"
20)
21
22// TMP
23// const (
24// // MinBigIntBytesLen defines the minimum bytes length of the minimum
25// // accepted value for the checked *big.Int
26// MinBigIntBytesLen = 20 * 8
27// )
28
29var (
30 // G represents the base point of secp256k1
31 G *Point = &Point{
32 X: btcec.S256().Gx,
33 Y: btcec.S256().Gy,
34 }
35
36 // N represents the order of G of secp256k1
37 N *big.Int = btcec.S256().N
38
39 zero *big.Int = big.NewInt(0)
40)
41
42// Point represents a point on the secp256k1 curve
43type Point struct {
44 X *big.Int
45 Y *big.Int
46}
47
48// Add performs the Point addition
49func (p *Point) Add(q *Point) *Point {
50 x, y := btcec.S256().Add(p.X, p.Y, q.X, q.Y)
51 return &Point{
52 X: x,
53 Y: y,
54 }
55}
56
57// Mul performs the Point scalar multiplication
58func (p *Point) Mul(scalar *big.Int) *Point {
59 x, y := btcec.S256().ScalarMult(p.X, p.Y, scalar.Bytes())
60 return &Point{
61 X: x,
62 Y: y,
63 }
64}
65
66func (p *Point) isValid() error {
67 if !btcec.S256().IsOnCurve(p.X, p.Y) {
68 return fmt.Errorf("Point is not on secp256k1")
69 }
70
71 if bytes.Equal(p.X.Bytes(), zero.Bytes()) &&
72 bytes.Equal(p.Y.Bytes(), zero.Bytes()) {
73 return fmt.Errorf("Point (%s, %s) can not be (0, 0)",
74 p.X.String(), p.Y.String())
75 }
76 return nil
77}
78
79// WIP
80func newRand() *big.Int {
81 var b [32]byte
82 _, err := rand.Read(b[:])
83 if err != nil {
84 panic(err)
85 }
86 bi := new(big.Int).SetBytes(b[:])
87 return new(big.Int).Mod(bi, N)
88}
89
90// PrivateKey represents the signer's private key
91type PrivateKey big.Int
92
93// PublicKey represents the signer's public key
94type PublicKey Point
95
96// NewPrivateKey returns a new random private key
97func NewPrivateKey() *PrivateKey {
98 k := newRand()
99 sk := PrivateKey(*k)
100 return &sk
101}
102
103// BigInt returns a *big.Int representation of the PrivateKey
104func (sk *PrivateKey) BigInt() *big.Int {
105 return (*big.Int)(sk)
106}
107
108// Public returns the PublicKey from the PrivateKey
109func (sk *PrivateKey) Public() *PublicKey {
110 Q := G.Mul(sk.BigInt())
111 pk := PublicKey(*Q)
112 return &pk
113}
114
115// Point returns a *Point representation of the PublicKey
116func (pk *PublicKey) Point() *Point {
117 return (*Point)(pk)
118}
119
120// NewRequestParameters returns a new random k (secret) & R (public) parameters
121func NewRequestParameters() (*big.Int, *Point) {
122 k := newRand()
123 return k, G.Mul(k) // R = kG
124}
125
126// BlindSign performs the blind signature on the given mBlinded using the
127// PrivateKey and the secret k values
128func (sk *PrivateKey) BlindSign(mBlinded *big.Int, k *big.Int) (*big.Int, error) {
129 // TODO add pending checks
130 if mBlinded.Cmp(N) != -1 {
131 return nil, fmt.Errorf("mBlinded not inside the finite field")
132 }
133 if bytes.Equal(mBlinded.Bytes(), big.NewInt(0).Bytes()) {
134 return nil, fmt.Errorf("mBlinded can not be 0")
135 }
136 // TMP
137 // if mBlinded.BitLen() < MinBigIntBytesLen {
138 // return nil, fmt.Errorf("mBlinded too small")
139 // }
140
141 // s' = dm' + k
142 sBlind := new(big.Int).Add(
143 new(big.Int).Mul(sk.BigInt(), mBlinded),
144 k)
145 sBlind = new(big.Int).Mod(sBlind, N)
146 return sBlind, nil
147}
148
149// UserSecretData contains the secret values from the User (a, b) and the
150// public F
151type UserSecretData struct {
152 A *big.Int
153 B *big.Int
154
155 F *Point // public (in the paper is named R)
156}
157
158// Blind performs the blinding operation on m using signerR parameter
159func Blind(m *big.Int, signerR *Point) (*big.Int, *UserSecretData, error) {
160 if err := signerR.isValid(); err != nil {
161 return nil, nil, fmt.Errorf("signerR %s", err)
162 }
163
164 u := &UserSecretData{}
165 u.A = newRand()
166 u.B = newRand()
167
168 // (R) F = aR' + bG
169 aR := signerR.Mul(u.A)
170 bG := G.Mul(u.B)
171 u.F = aR.Add(bG)
172
173 // TODO check that F != O (point at infinity)
174 if err := u.F.isValid(); err != nil {
175 return nil, nil, fmt.Errorf("u.F %s", err)
176 }
177
178 rx := new(big.Int).Mod(u.F.X, N)
179
180 // m' = a^-1 rx h(m)
181 ainv := new(big.Int).ModInverse(u.A, N)
182 ainvrx := new(big.Int).Mul(ainv, rx)
183 hBytes := crypto.Keccak256(m.Bytes())
184 h := new(big.Int).SetBytes(hBytes)
185 mBlinded := new(big.Int).Mul(ainvrx, h)
186 mBlinded = new(big.Int).Mod(mBlinded, N)
187
188 return mBlinded, u, nil
189}
190
191// Signature contains the signature values S & F
192type Signature struct {
193 S *big.Int
194 F *Point
195}
196
197// Unblind performs the unblinding operation of the blinded signature for the
198// given the UserSecretData
199func Unblind(sBlind *big.Int, u *UserSecretData) *Signature {
200 // s = a s' + b
201 as := new(big.Int).Mul(u.A, sBlind)
202 s := new(big.Int).Add(as, u.B)
203 s = new(big.Int).Mod(s, N)
204
205 return &Signature{
206 S: s,
207 F: u.F,
208 }
209}
210
211// Verify checks the signature of the message m for the given PublicKey
212func Verify(m *big.Int, s *Signature, q *PublicKey) bool {
213 // TODO add pending checks
214 if err := s.F.isValid(); err != nil {
215 return false
216 }
217 if err := q.Point().isValid(); err != nil {
218 return false
219 }
220
221 sG := G.Mul(s.S) // sG
222
223 hBytes := crypto.Keccak256(m.Bytes())
224 h := new(big.Int).SetBytes(hBytes)
225
226 rx := new(big.Int).Mod(s.F.X, N)
227 rxh := new(big.Int).Mul(rx, h)
228 // rxhG := G.Mul(rxh) // originally the paper uses G
229 rxhG := q.Point().Mul(rxh)
230
231 right := s.F.Add(rxhG)
232
233 // check sG == R + rx h(m) Q (where R in this code is F)
234 if bytes.Equal(sG.X.Bytes(), right.X.Bytes()) &&
235 bytes.Equal(sG.Y.Bytes(), right.Y.Bytes()) {
236 return true
237 }
238 return false
239}