arnaucube
arnaucube/go-blindsecp256k1Public Self-hosted repository
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}