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.st/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/ecdsa"
15 "crypto/rand"
16 "fmt"
17 "math/big"
18
19 "github.com/ethereum/go-ethereum/crypto"
20 "github.com/ethereum/go-ethereum/crypto/secp256k1"
21)
22
23var (
24 s256 *secp256k1.BitCurve = secp256k1.S256()
25 zero *big.Int = big.NewInt(0)
26
27 // B (from y^2 = x^3 + B)
28 B *big.Int = s256.B
29
30 // P represents the secp256k1 finite field
31 P *big.Int = s256.P
32
33 // G represents the base point of secp256k1
34 G *Point = &Point{
35 X: s256.Gx,
36 Y: s256.Gy,
37 }
38
39 // N represents the order of G of secp256k1
40 N *big.Int = s256.N
41)
42
43// Point represents a point on the secp256k1 curve
44type Point struct {
45 X *big.Int
46 Y *big.Int
47}
48
49// Add performs the Point addition
50func (p *Point) Add(q *Point) *Point {
51 x, y := s256.Add(p.X, p.Y, q.X, q.Y)
52 return &Point{
53 X: x,
54 Y: y,
55 }
56}
57
58// Mul performs the Point scalar multiplication
59func (p *Point) Mul(scalar *big.Int) *Point {
60 x, y := s256.ScalarMult(p.X, p.Y, scalar.Bytes())
61 return &Point{
62 X: x,
63 Y: y,
64 }
65}
66
67func (p *Point) isValid() error {
68 if !s256.IsOnCurve(p.X, p.Y) {
69 return fmt.Errorf("Point is not on secp256k1")
70 }
71
72 if bytes.Equal(p.X.Bytes(), zero.Bytes()) &&
73 bytes.Equal(p.Y.Bytes(), zero.Bytes()) {
74 return fmt.Errorf("Point (%s, %s) can not be (0, 0)",
75 p.X.String(), p.Y.String())
76 }
77 return nil
78}
79
80// Compress packs a Point to a byte array of 33 bytes, encoded in
81// little-endian.
82func (p *Point) Compress() [33]byte {
83 xBytes := p.X.Bytes()
84 odd := byte(0)
85 if isOdd(p.Y) {
86 odd = byte(1)
87 }
88 var b [33]byte
89 copy(b[32-len(xBytes):32], xBytes)
90 b[32] = odd
91 return b
92}
93
94func isOdd(b *big.Int) bool {
95 return b.Bit(0) != 0
96}
97
98// DecompressPoint unpacks a Point from the given byte array of 33 bytes
99// https://bitcointalk.org/index.php?topic=162805.msg1712294#msg1712294
100func DecompressPoint(b [33]byte) (*Point, error) {
101 x := new(big.Int).SetBytes(b[:32])
102 var odd bool
103 if b[32] == byte(1) {
104 odd = true
105 }
106
107 // secp256k1: y2 = x3+ ax2 + b (where A==0, B==7)
108
109 // compute x^3 + B mod p
110 x3 := new(big.Int).Mul(x, x)
111 x3 = new(big.Int).Mul(x3, x)
112 // x3 := new(big.Int).Exp(x, big.NewInt(3), nil)
113 x3 = new(big.Int).Add(x3, B)
114 x3 = new(big.Int).Mod(x3, P)
115
116 // sqrt mod p of x^3 + B
117 y := new(big.Int).ModSqrt(x3, P)
118 if y == nil {
119 return nil, fmt.Errorf("not sqrt mod of x^3")
120 }
121 if odd != isOdd(y) {
122 y = new(big.Int).Sub(P, y)
123 // TODO if needed Mod
124 }
125
126 // check that y is a square root of x^3 + B
127 y2 := new(big.Int).Mul(y, y)
128 y2 = new(big.Int).Mod(y2, P)
129 if !bytes.Equal(y2.Bytes(), x3.Bytes()) {
130 return nil, fmt.Errorf("invalid square root")
131 }
132
133 if odd != isOdd(y) {
134 return nil, fmt.Errorf("odd does not match oddness")
135 }
136
137 p := &Point{X: x, Y: y}
138 return p, p.isValid()
139}
140
141// WIP
142func newRand() (*big.Int, error) {
143 pk, err := ecdsa.GenerateKey(s256, rand.Reader)
144 if err != nil {
145 return nil, err
146 }
147 return pk.D, nil
148}
149
150// PrivateKey represents the signer's private key
151type PrivateKey big.Int
152
153// PublicKey represents the signer's public key
154type PublicKey Point
155
156// NewPrivateKey returns a new random private key
157func NewPrivateKey() (*PrivateKey, error) {
158 k, err := newRand()
159 if err != nil {
160 return nil, err
161 }
162 if err := checkBigIntSize(k); err != nil {
163 return nil, fmt.Errorf("k error: %s", err)
164 }
165 sk := PrivateKey(*k)
166 return &sk, nil
167}
168
169// BigInt returns a *big.Int representation of the PrivateKey
170func (sk *PrivateKey) BigInt() *big.Int {
171 return (*big.Int)(sk)
172}
173
174// Public returns the PublicKey from the PrivateKey
175func (sk *PrivateKey) Public() *PublicKey {
176 q := G.Mul(sk.BigInt())
177 pk := PublicKey(*q)
178 return &pk
179}
180
181// Point returns a *Point representation of the PublicKey
182func (pk *PublicKey) Point() *Point {
183 return (*Point)(pk)
184}
185
186// NewRequestParameters returns a new random k (secret) & R (public) parameters
187func NewRequestParameters() (*big.Int, *Point, error) {
188 k, err := newRand()
189 if err != nil {
190 return nil, nil, err
191 }
192 // k, R = kG
193 return k, G.Mul(k), nil
194}
195
196func checkBigIntSize(b *big.Int) error {
197 // check b.Bytes()==32, as go returns big-endian representation of the
198 // bigint, so if length is not 32 we have a smaller value than expected
199 // if len(b.Bytes()) != 32 { //nolint:gomnd
200 // return fmt.Errorf("invalid length, need 32 bytes")
201 // }
202 return nil
203}
204
205// BlindSign performs the blind signature on the given mBlinded using the
206// PrivateKey and the secret k values.
207func (sk *PrivateKey) BlindSign(mBlinded *big.Int, k *big.Int) (*big.Int, error) {
208 // TODO add pending checks
209 if mBlinded.Cmp(N) != -1 {
210 return nil, fmt.Errorf("mBlinded not inside the finite field")
211 }
212 if bytes.Equal(mBlinded.Bytes(), big.NewInt(0).Bytes()) {
213 return nil, fmt.Errorf("mBlinded can not be 0")
214 }
215 if err := checkBigIntSize(mBlinded); err != nil {
216 return nil, fmt.Errorf("mBlinded error: %s", err)
217 }
218 if err := checkBigIntSize(k); err != nil {
219 return nil, fmt.Errorf("k error: %s", err)
220 }
221
222 // s' = dm' + k
223 sBlind := new(big.Int).Add(
224 new(big.Int).Mul(sk.BigInt(), mBlinded),
225 k)
226 sBlind = new(big.Int).Mod(sBlind, N)
227 return sBlind, nil
228}
229
230// UserSecretData contains the secret values from the User (a, b) and the
231// public F
232type UserSecretData struct {
233 A *big.Int
234 B *big.Int
235
236 F *Point // public (in the paper is named R)
237}
238
239// Blind performs the blinding operation on m using signerR parameter
240func Blind(m *big.Int, signerR *Point) (*big.Int, *UserSecretData, error) {
241 if err := signerR.isValid(); err != nil {
242 return nil, nil, fmt.Errorf("signerR %s", err)
243 }
244
245 var err error
246 u := &UserSecretData{}
247 u.A, err = newRand()
248 if err != nil {
249 return nil, nil, err
250 }
251 u.B, err = newRand()
252 if err != nil {
253 return nil, nil, err
254 }
255
256 // (R) F = aR' + bG
257 aR := signerR.Mul(u.A)
258 bG := G.Mul(u.B)
259 u.F = aR.Add(bG)
260
261 if err := u.F.isValid(); err != nil {
262 return nil, nil, fmt.Errorf("u.F %s", err)
263 }
264
265 rx := new(big.Int).Mod(u.F.X, N)
266
267 // m' = a^-1 rx h(m)
268 ainv := new(big.Int).ModInverse(u.A, N)
269 ainvrx := new(big.Int).Mul(ainv, rx)
270 hBytes := crypto.Keccak256(m.Bytes())
271 h := new(big.Int).SetBytes(hBytes)
272 mBlinded := new(big.Int).Mul(ainvrx, h)
273 mBlinded = new(big.Int).Mod(mBlinded, N)
274
275 return mBlinded, u, nil
276}
277
278// Signature contains the signature values S & F
279type Signature struct {
280 S *big.Int
281 F *Point
282}
283
284// Compress packs a Signature to a byte array of 65 bytes, encoded in
285// little-endian.
286func (s *Signature) Compress() [65]byte {
287 var b [65]byte
288 sBytes := s.S.Bytes()
289 fBytes := s.F.Compress()
290 copy(b[:32], swapEndianness(sBytes))
291 copy(b[32:], fBytes[:])
292 return b
293}
294
295// DecompressSignature unpacks a Signature from the given byte array of 65 bytes
296func DecompressSignature(b [65]byte) (*Signature, error) {
297 s := new(big.Int).SetBytes(swapEndianness(b[:32]))
298 var fBytes [33]byte
299 copy(fBytes[:], b[32:])
300 f, err := DecompressPoint(fBytes)
301 if err != nil {
302 return nil, err
303 }
304 sig := &Signature{S: s, F: f}
305 return sig, nil
306}
307
308// Unblind performs the unblinding operation of the blinded signature for the
309// given the UserSecretData
310func Unblind(sBlind *big.Int, u *UserSecretData) *Signature {
311 // s = a s' + b
312 as := new(big.Int).Mul(u.A, sBlind)
313 s := new(big.Int).Add(as, u.B)
314 s = new(big.Int).Mod(s, N)
315
316 return &Signature{
317 S: s,
318 F: u.F,
319 }
320}
321
322// Verify checks the signature of the message m for the given PublicKey
323func Verify(m *big.Int, s *Signature, q *PublicKey) bool {
324 // TODO add pending checks
325 if err := s.F.isValid(); err != nil {
326 return false
327 }
328 if err := q.Point().isValid(); err != nil {
329 return false
330 }
331
332 sG := G.Mul(s.S) // sG
333
334 hBytes := crypto.Keccak256(m.Bytes())
335 h := new(big.Int).SetBytes(hBytes)
336
337 rx := new(big.Int).Mod(s.F.X, N)
338 rxh := new(big.Int).Mul(rx, h)
339 // do mod, as go-ethereum/crypto/secp256k1 can not handle scalars > 256 bits
340 rxhMod := new(big.Int).Mod(rxh, N)
341 // rxhG := G.Mul(rxh) // originally the paper uses G
342 rxhG := q.Point().Mul(rxhMod)
343
344 right := s.F.Add(rxhG)
345
346 // check sG == R + rx h(m) Q (where R in this code is F)
347 if bytes.Equal(sG.X.Bytes(), right.X.Bytes()) &&
348 bytes.Equal(sG.Y.Bytes(), right.Y.Bytes()) {
349 return true
350 }
351 return false
352}