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