arnaucube
arnaucube/go-blindsecp256k1Public Self-hosted repository
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/arnaucube/go-blindsecp256k1"
 18)
 19
 20// WIP
 21func newRand() *big.Int {
 22	var b [32]byte
 23	_, err := rand.Read(b[:])
 24	if err != nil {
 25		panic(err)
 26	}
 27	bi := new(big.Int).SetBytes(b[:])
 28	return new(big.Int).Mod(bi, blindsecp256k1.N)
 29}
 30
 31// PrivateKey represents the signer's private key
 32type PrivateKey big.Int
 33
 34// NewPrivateKey returns a new random private key
 35func NewPrivateKey() *PrivateKey {
 36	k := newRand()
 37	sk := PrivateKey(*k)
 38	return &sk
 39}
 40
 41// BigInt returns a *big.Int representation of the PrivateKey
 42func (sk *PrivateKey) BigInt() *big.Int {
 43	return (*big.Int)(sk)
 44}
 45
 46// Public returns the PublicKey from the PrivateKey
 47func (sk *PrivateKey) Public() *blindsecp256k1.PublicKey {
 48	Q := blindsecp256k1.G.Mul(sk.BigInt())
 49	pk := blindsecp256k1.PublicKey(*Q)
 50	return &pk
 51}
 52
 53// NewRequestParameters returns a new random k (secret) & R (public) parameters
 54func NewRequestParameters() (*big.Int, *blindsecp256k1.Point) {
 55	k := newRand()
 56	return k, blindsecp256k1.G.Mul(k) // R = kG
 57}
 58
 59// BlindSign performs the blind signature on the given mBlinded using
 60// SignerPrivateData values
 61func (sk *PrivateKey) BlindSign(mBlinded *big.Int, k *big.Int) *big.Int {
 62	// TODO add pending checks
 63	// s' = d(m') + k
 64	sBlind := new(big.Int).Add(
 65		new(big.Int).Mul(sk.BigInt(), mBlinded),
 66		k)
 67	return sBlind
 68}
 69
 70// UserSecretData contains the secret values from the User (a, b, c) and the
 71// public F
 72type UserSecretData struct {
 73	A *big.Int
 74	B *big.Int
 75	C *big.Int
 76
 77	F *blindsecp256k1.Point // public
 78}
 79
 80// Blind performs the blinding operation on m using SignerPublicData parameters
 81func Blind(m *big.Int, signerPubK *blindsecp256k1.PublicKey,
 82	signerR *blindsecp256k1.Point) (*big.Int, *UserSecretData) {
 83	u := &UserSecretData{}
 84	u.A = newRand()
 85	u.B = newRand()
 86	u.C = newRand()
 87	binv := new(big.Int).ModInverse(u.B, blindsecp256k1.N)
 88
 89	// F = b^-1 R + a b^-1 Q + c G
 90	bR := signerR.Mul(binv)
 91	abinv := new(big.Int).Mul(u.A, binv)
 92	abinv = new(big.Int).Mod(abinv, blindsecp256k1.N)
 93	abQ := signerPubK.Point().Mul(abinv)
 94	cG := blindsecp256k1.G.Mul(u.C)
 95	u.F = bR.Add(abQ).Add(cG)
 96	// TODO check F==O
 97
 98	r := new(big.Int).Mod(u.F.X, blindsecp256k1.N)
 99
100	// m' = br(m)+a
101	br := new(big.Int).Mul(u.B, r)
102	brm := new(big.Int).Mul(br, m)
103	mBlinded := new(big.Int).Add(brm, u.A)
104	mBlinded = new(big.Int).Mod(mBlinded, blindsecp256k1.N)
105	return mBlinded, u
106}
107
108// Signature contains the signature values S & F
109type Signature struct {
110	S *big.Int
111	F *blindsecp256k1.Point
112}
113
114// Unblind performs the unblinding operation of the blinded signature for the
115// given message m and the UserSecretData
116func Unblind(sBlind, m *big.Int, u *UserSecretData) *Signature {
117	// s = b^-1 s' + c
118	binv := new(big.Int).ModInverse(u.B, blindsecp256k1.N)
119	bs := new(big.Int).Mul(binv, sBlind)
120	s := new(big.Int).Add(bs, u.C)
121	s = new(big.Int).Mod(s, blindsecp256k1.N)
122
123	return &Signature{
124		S: s,
125		F: u.F,
126	}
127}
128
129// Verify checks the signature of the message m for the given PublicKey
130func Verify(m *big.Int, signature *Signature, q *blindsecp256k1.PublicKey) bool {
131	// TODO add pending checks
132	sG := blindsecp256k1.G.Mul(signature.S) // sG
133
134	r := new(big.Int).Mod(signature.F.X, blindsecp256k1.N) // r = Fx mod N
135	rm := new(big.Int).Mul(r, m)
136	rm = new(big.Int).Mod(rm, blindsecp256k1.N)
137	rmQ := q.Point().Mul(rm)
138	rmQF := rmQ.Add(signature.F) // rmQ + F
139
140	// check sG == rmQ + F
141	if bytes.Equal(sG.X.Bytes(), rmQF.X.Bytes()) &&
142		bytes.Equal(sG.Y.Bytes(), rmQF.Y.Bytes()) {
143		return true
144	}
145	return false
146}