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}