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 "encoding/json"
16 "fmt"
17 "math/big"
18
19 "github.com/btcsuite/btcd/btcec"
20 "github.com/ethereum/go-ethereum/crypto"
21)
22
23var (
24 // G represents the base point of secp256k1
25 G *Point = &Point{
26 X: btcec.S256().Gx,
27 Y: btcec.S256().Gy,
28 }
29
30 // N represents the order of G of secp256k1
31 N *big.Int = btcec.S256().N
32)
33
34// Point represents a point on the secp256k1 curve
35type Point struct {
36 X *big.Int
37 Y *big.Int
38}
39
40// Add performs the Point addition
41func (p *Point) Add(q *Point) *Point {
42 x, y := btcec.S256().Add(p.X, p.Y, q.X, q.Y)
43 return &Point{
44 X: x,
45 Y: y,
46 }
47}
48
49// Mul performs the Point scalar multiplication
50func (p *Point) Mul(scalar *big.Int) *Point {
51 x, y := btcec.S256().ScalarMult(p.X, p.Y, scalar.Bytes())
52 return &Point{
53 X: x,
54 Y: y,
55 }
56}
57
58// MarshalJSON implements the json marshaler for the Point
59func (p Point) MarshalJSON() ([]byte, error) {
60 return json.Marshal(&struct {
61 X string `json:"x"`
62 Y string `json:"y"`
63 }{
64 X: p.X.String(),
65 Y: p.Y.String(),
66 })
67}
68
69// UnmarshalJSON implements the json unmarshaler for the Point
70func (p *Point) UnmarshalJSON(b []byte) error {
71 aux := &struct {
72 X string `json:"x"`
73 Y string `json:"y"`
74 }{}
75 err := json.Unmarshal(b, &aux)
76 if err != nil {
77 return err
78 }
79 x, ok := new(big.Int).SetString(aux.X, 10)
80 if !ok {
81 return fmt.Errorf("Can not parse Point.X %s", aux.X)
82 }
83 y, ok := new(big.Int).SetString(aux.Y, 10)
84 if !ok {
85 return fmt.Errorf("Can not parse Point.Y %s", aux.Y)
86 }
87 p.X = x
88 p.Y = y
89 return nil
90}
91
92// WIP
93func newRand() *big.Int {
94 var b [32]byte
95 _, err := rand.Read(b[:])
96 if err != nil {
97 panic(err)
98 }
99 bi := new(big.Int).SetBytes(b[:])
100 return new(big.Int).Mod(bi, N)
101}
102
103// PrivateKey represents the signer's private key
104type PrivateKey big.Int
105
106// PublicKey represents the signer's public key
107type PublicKey Point
108
109// MarshalJSON implements the json marshaler for the PublicKey
110func (pk PublicKey) MarshalJSON() ([]byte, error) {
111 return json.Marshal(pk.Point())
112}
113
114// UnmarshalJSON implements the json unmarshaler for the PublicKey
115func (pk *PublicKey) UnmarshalJSON(b []byte) error {
116 var point *Point
117 err := json.Unmarshal(b, &point)
118 if err != nil {
119 return err
120 }
121 pk.X = point.X
122 pk.Y = point.Y
123 return nil
124}
125
126// NewPrivateKey returns a new random private key
127func NewPrivateKey() *PrivateKey {
128 k := newRand()
129 sk := PrivateKey(*k)
130 return &sk
131}
132
133// BigInt returns a *big.Int representation of the PrivateKey
134func (sk *PrivateKey) BigInt() *big.Int {
135 return (*big.Int)(sk)
136}
137
138// Public returns the PublicKey from the PrivateKey
139func (sk *PrivateKey) Public() *PublicKey {
140 Q := G.Mul(sk.BigInt())
141 pk := PublicKey(*Q)
142 return &pk
143}
144
145// Point returns a *Point representation of the PublicKey
146func (pk *PublicKey) Point() *Point {
147 return (*Point)(pk)
148}
149
150// NewRequestParameters returns a new random k (secret) & R (public) parameters
151func NewRequestParameters() (*big.Int, *Point) {
152 k := newRand()
153 return k, G.Mul(k) // R = kG
154}
155
156// BlindSign performs the blind signature on the given mBlinded using the
157// PrivateKey and the secret k values
158func (sk *PrivateKey) BlindSign(mBlinded *big.Int, k *big.Int) *big.Int {
159 // TODO add pending checks
160 // s' = dm' + k
161 sBlind := new(big.Int).Add(
162 new(big.Int).Mul(sk.BigInt(), mBlinded),
163 k)
164 return sBlind
165}
166
167// UserSecretData contains the secret values from the User (a, b, c) and the
168// public F
169type UserSecretData struct {
170 A *big.Int
171 B *big.Int
172
173 F *Point // public (in the paper is R)
174}
175
176// Blind performs the blinding operation on m using signerR parameter
177func Blind(m *big.Int, signerR *Point) (*big.Int, *UserSecretData) {
178 u := &UserSecretData{}
179 u.A = newRand()
180 u.B = newRand()
181
182 // (R) F = aR' + bG
183 aR := signerR.Mul(u.A)
184 bG := G.Mul(u.B)
185 u.F = aR.Add(bG)
186
187 // TODO check that F != O (point at infinity)
188
189 rx := new(big.Int).Mod(u.F.X, N)
190
191 // m' = a^-1 rx h(m)
192 ainv := new(big.Int).ModInverse(u.A, N)
193 ainvrx := new(big.Int).Mul(ainv, rx)
194 hBytes := crypto.Keccak256(m.Bytes())
195 h := new(big.Int).SetBytes(hBytes)
196 mBlinded := new(big.Int).Mul(ainvrx, h)
197
198 return mBlinded, u
199}
200
201// Signature contains the signature values S & F
202type Signature struct {
203 S *big.Int
204 F *Point
205}
206
207// MarshalJSON implements the json marshaler for the Signature
208func (sig Signature) MarshalJSON() ([]byte, error) {
209 return json.Marshal(&struct {
210 S string `json:"s"`
211 F struct {
212 X string `json:"x"`
213 Y string `json:"y"`
214 } `json:"f"`
215 }{
216 S: sig.S.String(),
217 F: struct {
218 X string `json:"x"`
219 Y string `json:"y"`
220 }{
221 X: sig.F.X.String(),
222 Y: sig.F.Y.String(),
223 },
224 })
225}
226
227// UnmarshalJSON implements the json unmarshaler for the Signature
228func (sig *Signature) UnmarshalJSON(b []byte) error {
229 aux := &struct {
230 S string `json:"s"`
231 F struct {
232 X string `json:"x"`
233 Y string `json:"y"`
234 } `json:"f"`
235 }{}
236 err := json.Unmarshal(b, &aux)
237 if err != nil {
238 return err
239 }
240
241 s, ok := new(big.Int).SetString(aux.S, 10)
242 if !ok {
243 return fmt.Errorf("Can not parse sig.S %s", aux.S)
244 }
245 sig.S = s
246
247 x, ok := new(big.Int).SetString(aux.F.X, 10)
248 if !ok {
249 return fmt.Errorf("Can not parse sig.F.X %s", aux.F.X)
250 }
251 y, ok := new(big.Int).SetString(aux.F.Y, 10)
252 if !ok {
253 return fmt.Errorf("Can not parse sig.F.Y %s", aux.F.Y)
254 }
255 sig.F = &Point{}
256 sig.F.X = x
257 sig.F.Y = y
258 return nil
259}
260
261// Unblind performs the unblinding operation of the blinded signature for the
262// given message m and the UserSecretData
263func Unblind(sBlind, m *big.Int, u *UserSecretData) *Signature {
264 // s = a s' + b
265 as := new(big.Int).Mul(u.A, sBlind)
266 s := new(big.Int).Add(as, u.B)
267
268 return &Signature{
269 S: s,
270 F: u.F,
271 }
272}
273
274// Verify checks the signature of the message m for the given PublicKey
275func Verify(m *big.Int, s *Signature, q *PublicKey) bool {
276 // TODO add pending checks
277
278 sG := G.Mul(s.S) // sG
279
280 hBytes := crypto.Keccak256(m.Bytes())
281 h := new(big.Int).SetBytes(hBytes)
282
283 rx := new(big.Int).Mod(s.F.X, N)
284 rxh := new(big.Int).Mul(rx, h)
285 // rxhG := G.Mul(rxh) // originally the paper uses G
286 rxhG := q.Point().Mul(rxh)
287
288 right := s.F.Add(rxhG)
289
290 // check sG == R + rx h(m) G (where R in this code is F)
291 if bytes.Equal(sG.X.Bytes(), right.X.Bytes()) &&
292 bytes.Equal(sG.Y.Bytes(), right.Y.Bytes()) {
293 return true
294 }
295 return false
296}