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