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/ecdsa"
15 "crypto/rand"
16 "math/big"
17
18 "github.com/arnaucube/go-blindsecp256k1"
19 "github.com/ethereum/go-ethereum/crypto/secp256k1"
20)
21
22// WIP
23func newRand() (*big.Int, error) {
24 pk, err := ecdsa.GenerateKey(secp256k1.S256(), rand.Reader)
25 if err != nil {
26 return nil, err
27 }
28 return pk.D, nil
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, error) {
36 k, err := newRand()
37 if err != nil {
38 return nil, err
39 }
40 sk := PrivateKey(*k)
41 return &sk, nil
42}
43
44// BigInt returns a *big.Int representation of the PrivateKey
45func (sk *PrivateKey) BigInt() *big.Int {
46 return (*big.Int)(sk)
47}
48
49// Public returns the PublicKey from the PrivateKey
50func (sk *PrivateKey) Public() *blindsecp256k1.PublicKey {
51 Q := blindsecp256k1.G.Mul(sk.BigInt())
52 pk := blindsecp256k1.PublicKey(*Q)
53 return &pk
54}
55
56// NewRequestParameters returns a new random k (secret) & R (public) parameters
57func NewRequestParameters() (*big.Int, *blindsecp256k1.Point, error) {
58 k, err := newRand()
59 if err != nil {
60 return nil, nil, err
61 }
62 // k, R = kG
63 return k, blindsecp256k1.G.Mul(k), nil
64}
65
66// BlindSign performs the blind signature on the given mBlinded using
67// SignerPrivateData values
68func (sk *PrivateKey) BlindSign(mBlinded *big.Int, k *big.Int) *big.Int {
69 // WARNING missing checks, this package is not updated, use
70 // blindsecp256k1 instead
71 // TODO add pending checks
72 // s' = d(m') + k
73 sBlind := new(big.Int).Add(
74 new(big.Int).Mul(sk.BigInt(), mBlinded),
75 k)
76 return sBlind
77}
78
79// UserSecretData contains the secret values from the User (a, b, c) and the
80// public F
81type UserSecretData struct {
82 A *big.Int
83 B *big.Int
84 C *big.Int
85
86 F *blindsecp256k1.Point // public
87}
88
89// Blind performs the blinding operation on m using SignerPublicData parameters
90func Blind(m *big.Int, signerPubK *blindsecp256k1.PublicKey,
91 signerR *blindsecp256k1.Point) (*big.Int, *UserSecretData, error) {
92 var err error
93 u := &UserSecretData{}
94 u.A, err = newRand()
95 if err != nil {
96 return nil, nil, err
97 }
98 u.B, err = newRand()
99 if err != nil {
100 return nil, nil, err
101 }
102 u.C, err = newRand()
103 if err != nil {
104 return nil, nil, err
105 }
106 binv := new(big.Int).ModInverse(u.B, blindsecp256k1.N)
107
108 // F = b^-1 R + a b^-1 Q + c G
109 bR := signerR.Mul(binv)
110 abinv := new(big.Int).Mul(u.A, binv)
111 abinv = new(big.Int).Mod(abinv, blindsecp256k1.N)
112 abQ := signerPubK.Point().Mul(abinv)
113 cG := blindsecp256k1.G.Mul(u.C)
114 u.F = bR.Add(abQ).Add(cG)
115 // TODO check F==O
116
117 r := new(big.Int).Mod(u.F.X, blindsecp256k1.N)
118
119 // m' = br(m)+a
120 br := new(big.Int).Mul(u.B, r)
121 brm := new(big.Int).Mul(br, m)
122 mBlinded := new(big.Int).Add(brm, u.A)
123 mBlinded = new(big.Int).Mod(mBlinded, blindsecp256k1.N)
124 return mBlinded, u, nil
125}
126
127// Signature contains the signature values S & F
128type Signature struct {
129 S *big.Int
130 F *blindsecp256k1.Point
131}
132
133// Unblind performs the unblinding operation of the blinded signature for the
134// given and the UserSecretData
135func Unblind(sBlind *big.Int, u *UserSecretData) *Signature {
136 // s = b^-1 s' + c
137 binv := new(big.Int).ModInverse(u.B, blindsecp256k1.N)
138 bs := new(big.Int).Mul(binv, sBlind)
139 s := new(big.Int).Add(bs, u.C)
140 s = new(big.Int).Mod(s, blindsecp256k1.N)
141
142 return &Signature{
143 S: s,
144 F: u.F,
145 }
146}
147
148// Verify checks the signature of the message m for the given PublicKey
149func Verify(m *big.Int, signature *Signature, q *blindsecp256k1.PublicKey) bool {
150 // TODO add pending checks
151 sG := blindsecp256k1.G.Mul(signature.S) // sG
152
153 r := new(big.Int).Mod(signature.F.X, blindsecp256k1.N) // r = Fx mod N
154 rm := new(big.Int).Mul(r, m)
155 rm = new(big.Int).Mod(rm, blindsecp256k1.N)
156 rmQ := q.Point().Mul(rm)
157 rmQF := rmQ.Add(signature.F) // rmQ + F
158
159 // check sG == rmQ + F
160 if bytes.Equal(sG.X.Bytes(), rmQF.X.Bytes()) &&
161 bytes.Equal(sG.Y.Bytes(), rmQF.Y.Bytes()) {
162 return true
163 }
164 return false
165}