go-blindsecp256k1/v0/blindsecp256k1v0.go
v0/blindsecp256k1v0.goRaw
1// Package blindsecp256k1v0 implements the Blind signature scheme explained at
2// "An Efficient Blind Signature Scheme Based on the Elliptic Curve Discrete
3// Logarithm Problem", by Morteza Nikooghadama & Ali Zakerolhosseini
4// http://www.isecure-journal.com/article_39171_47f9ec605dd3918c2793565ec21fcd7a.pdf
5//
6// LICENSE can be found at https://github.com/arnaucube/go-blindsecp256k1/blob/master/LICENSE
7//
8package blindsecp256k1v0
9
10// WARNING: WIP code
11
12import (
13 "bytes"
14 "crypto/rand"
15 "math/big"
16
17 "github.com/btcsuite/btcd/btcec"
18)
19
20var (
21 // G represents the base point of secp256k1
22 G *Point = &Point{
23 X: btcec.S256().Gx,
24 Y: btcec.S256().Gy,
25 }
26
27 // N represents the order of G of secp256k1
28 N *big.Int = btcec.S256().N
29)
30
31// Point represents a point on the secp256k1 curve
32type Point struct {
33 X *big.Int
34 Y *big.Int
35}
36
37// Add performs the Point addition
38func (p *Point) Add(q *Point) *Point {
39 x, y := btcec.S256().Add(p.X, p.Y, q.X, q.Y)
40 return &Point{
41 X: x,
42 Y: y,
43 }
44}
45
46// Mul performs the Point scalar multiplication
47func (p *Point) Mul(scalar *big.Int) *Point {
48 x, y := btcec.S256().ScalarMult(p.X, p.Y, scalar.Bytes())
49 return &Point{
50 X: x,
51 Y: y,
52 }
53}
54
55// WIP
56func newRand() *big.Int {
57 var b [32]byte
58 _, err := rand.Read(b[:])
59 if err != nil {
60 panic(err)
61 }
62 bi := new(big.Int).SetBytes(b[:])
63 return new(big.Int).Mod(bi, N)
64}
65
66// PrivateKey represents the signer's private key
67type PrivateKey big.Int
68
69// PublicKey represents the signer's public key
70type PublicKey Point
71
72// NewPrivateKey returns a new random private key
73func NewPrivateKey() *PrivateKey {
74 k := newRand()
75 sk := PrivateKey(*k)
76 return &sk
77}
78
79// BigInt returns a *big.Int representation of the PrivateKey
80func (sk *PrivateKey) BigInt() *big.Int {
81 return (*big.Int)(sk)
82}
83
84// Public returns the PublicKey from the PrivateKey
85func (sk *PrivateKey) Public() *PublicKey {
86 Q := G.Mul(sk.BigInt())
87 pk := PublicKey(*Q)
88 return &pk
89}
90
91// Point returns a *Point representation of the PublicKey
92func (pk *PublicKey) Point() *Point {
93 return (*Point)(pk)
94}
95
96// NewRequestParameters returns a new random k (secret) & R (public) parameters
97func NewRequestParameters() (*big.Int, *Point) {
98 k := newRand()
99 return k, G.Mul(k) // R = kG
100}
101
102// BlindSign performs the blind signature on the given mBlinded using
103// SignerPrivateData values
104func (sk *PrivateKey) BlindSign(mBlinded *big.Int, k *big.Int) *big.Int {
105 // TODO add pending checks
106 // s' = d(m') + k
107 sBlind := new(big.Int).Add(
108 new(big.Int).Mul(sk.BigInt(), mBlinded),
109 k)
110 return sBlind
111}
112
113// UserSecretData contains the secret values from the User (a, b, c) and the
114// public F
115type UserSecretData struct {
116 A *big.Int
117 B *big.Int
118 C *big.Int
119
120 F *Point // public
121}
122
123// Blind performs the blinding operation on m using SignerPublicData parameters
124func Blind(m *big.Int, signerPubK *PublicKey, signerR *Point) (*big.Int, *UserSecretData) {
125 u := &UserSecretData{}
126 u.A = newRand()
127 u.B = newRand()
128 u.C = newRand()
129 binv := new(big.Int).ModInverse(u.B, N)
130
131 // F = b^-1 R + a b^-1 Q + c G
132 bR := signerR.Mul(binv)
133 abinv := new(big.Int).Mul(u.A, binv)
134 abinv = new(big.Int).Mod(abinv, N)
135 abQ := signerPubK.Point().Mul(abinv)
136 cG := G.Mul(u.C)
137 u.F = bR.Add(abQ).Add(cG)
138 // TODO check F==O
139
140 r := new(big.Int).Mod(u.F.X, N)
141
142 // m' = br(m)+a
143 br := new(big.Int).Mul(u.B, r)
144 brm := new(big.Int).Mul(br, m)
145 mBlinded := new(big.Int).Add(brm, u.A)
146 mBlinded = new(big.Int).Mod(mBlinded, N)
147 return mBlinded, u
148}
149
150// Signature contains the signature values S & F
151type Signature struct {
152 S *big.Int
153 F *Point
154}
155
156// Unblind performs the unblinding operation of the blinded signature for the
157// given message m and the UserSecretData
158func Unblind(sBlind, m *big.Int, u *UserSecretData) *Signature {
159 // s = b^-1 s' + c
160 binv := new(big.Int).ModInverse(u.B, N)
161 bs := new(big.Int).Mul(binv, sBlind)
162 s := new(big.Int).Add(bs, u.C)
163 s = new(big.Int).Mod(s, N)
164
165 return &Signature{
166 S: s,
167 F: u.F,
168 }
169}
170
171// Verify checks the signature of the message m for the given PublicKey
172func Verify(m *big.Int, signature *Signature, q *PublicKey) bool {
173 // TODO add pending checks
174 sG := G.Mul(signature.S) // sG
175
176 r := new(big.Int).Mod(signature.F.X, N) // r = Fx mod N
177 rm := new(big.Int).Mul(r, m)
178 rm = new(big.Int).Mod(rm, N)
179 rmQ := q.Point().Mul(rm)
180 rmQF := rmQ.Add(signature.F) // rmQ + F
181
182 // check sG == rmQ + F
183 if bytes.Equal(sG.X.Bytes(), rmQF.X.Bytes()) &&
184 bytes.Equal(sG.Y.Bytes(), rmQF.Y.Bytes()) {
185 return true
186 }
187 return false
188}