mirror of
https://github.com/arnaucube/go-blindsecp256k1.git
synced 2026-02-06 19:16:40 +01:00
Migrate to geth/secp256k1, add checks
Migrate from btcd/btcec to go-ethereum/crypto/secp256k1 Abstract calls on secp256k1.S256() Change newRand approach, use ecdsa.GenerateKey underneath Add check of size of mBlinded & k when blind signing
This commit is contained in:
41
README.md
41
README.md
@@ -1,9 +1,11 @@
|
||||
# go-blindsecp256k1 [](https://godoc.org/github.com/arnaucube/go-blindsecp256k1) [](https://goreportcard.com/report/github.com/arnaucube/go-blindsecp256k1) [](https://github.com/arnaucube/go-blindsecp256k1/actions?query=workflow%3ATest)
|
||||
|
||||
Blind signature over [secp256k1](https://en.bitcoin.it/wiki/Secp256k1), based on *"[New Blind Signature Schemes Based on the (Elliptic Curve) Discrete Logarithm Problem](https://sci-hub.do/10.1109/ICCKE.2013.6682844)"* paper by Hamid Mala & Nafiseh Nezhadansari.
|
||||
Blind signature over [secp256k1](https://en.bitcoin.it/wiki/Secp256k1), based on *"[New Blind Signature Schemes Based on the (Elliptic Curve) Discrete Logarithm Problem](https://sci-hub.st/10.1109/iccke.2013.6682844)"* paper by Hamid Mala & Nafiseh Nezhadansari.
|
||||
|
||||
**WARNING**: this repo is experimental, do not use in production.
|
||||
|
||||
The implementation of this repo is compatible with https://github.com/arnaucube/blindsecp256k1-js
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
@@ -13,23 +15,22 @@ import (
|
||||
)
|
||||
|
||||
[...]
|
||||
// errors are not handled for simplicity of the example
|
||||
|
||||
// signer: create new signer key pair
|
||||
sk := blindsecp256k1.NewPrivateKey()
|
||||
sk, _ := blindsecp256k1.NewPrivateKey()
|
||||
signerPubK := sk.Public()
|
||||
|
||||
// signer: when user requests new R parameter to blind a new msg,
|
||||
// create new signerR (public) with its secret k
|
||||
k, signerR := blindsecp256k1.NewRequestParameters()
|
||||
k, signerR, _ := blindsecp256k1.NewRequestParameters()
|
||||
|
||||
// user: blinds the msg using signer's R
|
||||
msg := new(big.Int).SetBytes([]byte("test"))
|
||||
msgBlinded, userSecretData, err := blindsecp256k1.Blind(msg, signerR)
|
||||
require.Nil(t, err)
|
||||
msgBlinded, userSecretData, _ := blindsecp256k1.Blind(msg, signerR)
|
||||
|
||||
// signer: signs the blinded message using its private key & secret k
|
||||
sBlind, err := sk.BlindSign(msgBlinded, k)
|
||||
require.Nil(t, err)
|
||||
sBlind, _ := sk.BlindSign(msgBlinded, k)
|
||||
|
||||
// user: unblinds the blinded signature
|
||||
sig := blindsecp256k1.Unblind(sBlind, userSecretData)
|
||||
@@ -39,5 +40,31 @@ verified := blindsecp256k1.Verify(msg, sig, signerPubK)
|
||||
assert.True(t, verified)
|
||||
```
|
||||
|
||||
Compression & decompression (allows to compress a point & public key (64 bytes) into 33 bytes, and a signature (96 bytes) into 65 bytes):
|
||||
```go
|
||||
p := blindsecp256k1.G // take the generator point as an example
|
||||
|
||||
// also, instead from G, we can start from a PublicKey, which can be converted
|
||||
// into a Point with
|
||||
p = pk.Point()
|
||||
|
||||
// compress point
|
||||
b := p.Compress()
|
||||
fmt.Println(hex.EncodeToString(b[:]))
|
||||
|
||||
// decompress point (recovering the original point)
|
||||
p2, _ := blindsecp256k1.DecompressPoint(b)
|
||||
assert.Equal(t, p, p2)
|
||||
|
||||
|
||||
// compress signature
|
||||
b = sig.Compress()
|
||||
fmt.Println(hex.EncodeToString(b[:])) // 65 bytes
|
||||
|
||||
// decompress signature
|
||||
sig2, _ := DecompressSignature(b)
|
||||
assert.Equal(t, sig, sig2)
|
||||
```
|
||||
|
||||
## WASM usage
|
||||
WASM wrappers for browser usage can be found at the [wasm](https://github.com/arnaucube/go-blindsecp256k1/tree/master/wasm/) directory with an example in html&js.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Package blindsecp256k1 implements the Blind signature scheme explained at
|
||||
// "New Blind Signature Schemes Based on the (Elliptic Curve) Discrete
|
||||
// Logarithm Problem", by Hamid Mala & Nafiseh Nezhadansari
|
||||
// https://sci-hub.do/10.1109/ICCKE.2013.6682844
|
||||
// https://sci-hub.st/10.1109/ICCKE.2013.6682844
|
||||
//
|
||||
// LICENSE can be found at https://github.com/arnaucube/go-blindsecp256k1/blob/master/LICENSE
|
||||
//
|
||||
@@ -11,42 +11,33 @@ package blindsecp256k1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
)
|
||||
|
||||
// TMP
|
||||
// const (
|
||||
// // MinBigIntBytesLen defines the minimum bytes length of the minimum
|
||||
// // accepted value for the checked *big.Int
|
||||
// MinBigIntBytesLen = 20 * 8
|
||||
// )
|
||||
|
||||
var (
|
||||
zero *big.Int = big.NewInt(0)
|
||||
s256 *secp256k1.BitCurve = secp256k1.S256()
|
||||
zero *big.Int = big.NewInt(0)
|
||||
|
||||
// B (from y^2 = x^3 + B)
|
||||
B *big.Int = btcec.S256().B
|
||||
B *big.Int = s256.B
|
||||
|
||||
// P represents the secp256k1 finite field
|
||||
P *big.Int = btcec.S256().P
|
||||
|
||||
// Q = (P+1)/4
|
||||
Q = new(big.Int).Div(new(big.Int).Add(P,
|
||||
big.NewInt(1)), big.NewInt(4)) // nolint:gomnd
|
||||
P *big.Int = s256.P
|
||||
|
||||
// G represents the base point of secp256k1
|
||||
G *Point = &Point{
|
||||
X: btcec.S256().Gx,
|
||||
Y: btcec.S256().Gy,
|
||||
X: s256.Gx,
|
||||
Y: s256.Gy,
|
||||
}
|
||||
|
||||
// N represents the order of G of secp256k1
|
||||
N *big.Int = btcec.S256().N
|
||||
N *big.Int = s256.N
|
||||
)
|
||||
|
||||
// Point represents a point on the secp256k1 curve
|
||||
@@ -57,7 +48,7 @@ type Point struct {
|
||||
|
||||
// Add performs the Point addition
|
||||
func (p *Point) Add(q *Point) *Point {
|
||||
x, y := btcec.S256().Add(p.X, p.Y, q.X, q.Y)
|
||||
x, y := s256.Add(p.X, p.Y, q.X, q.Y)
|
||||
return &Point{
|
||||
X: x,
|
||||
Y: y,
|
||||
@@ -66,7 +57,7 @@ func (p *Point) Add(q *Point) *Point {
|
||||
|
||||
// Mul performs the Point scalar multiplication
|
||||
func (p *Point) Mul(scalar *big.Int) *Point {
|
||||
x, y := btcec.S256().ScalarMult(p.X, p.Y, scalar.Bytes())
|
||||
x, y := s256.ScalarMult(p.X, p.Y, scalar.Bytes())
|
||||
return &Point{
|
||||
X: x,
|
||||
Y: y,
|
||||
@@ -74,7 +65,7 @@ func (p *Point) Mul(scalar *big.Int) *Point {
|
||||
}
|
||||
|
||||
func (p *Point) isValid() error {
|
||||
if !btcec.S256().IsOnCurve(p.X, p.Y) {
|
||||
if !s256.IsOnCurve(p.X, p.Y) {
|
||||
return fmt.Errorf("Point is not on secp256k1")
|
||||
}
|
||||
|
||||
@@ -147,14 +138,12 @@ func DecompressPoint(b [33]byte) (*Point, error) {
|
||||
}
|
||||
|
||||
// WIP
|
||||
func newRand() *big.Int {
|
||||
var b [32]byte
|
||||
_, err := rand.Read(b[:])
|
||||
func newRand() (*big.Int, error) {
|
||||
pk, err := ecdsa.GenerateKey(s256, rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
bi := new(big.Int).SetBytes(b[:])
|
||||
return new(big.Int).Mod(bi, N)
|
||||
return pk.D, nil
|
||||
}
|
||||
|
||||
// PrivateKey represents the signer's private key
|
||||
@@ -164,10 +153,16 @@ type PrivateKey big.Int
|
||||
type PublicKey Point
|
||||
|
||||
// NewPrivateKey returns a new random private key
|
||||
func NewPrivateKey() *PrivateKey {
|
||||
k := newRand()
|
||||
func NewPrivateKey() (*PrivateKey, error) {
|
||||
k, err := newRand()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := checkBigIntSize(k); err != nil {
|
||||
return nil, fmt.Errorf("k error: %s", err)
|
||||
}
|
||||
sk := PrivateKey(*k)
|
||||
return &sk
|
||||
return &sk, nil
|
||||
}
|
||||
|
||||
// BigInt returns a *big.Int representation of the PrivateKey
|
||||
@@ -177,8 +172,8 @@ func (sk *PrivateKey) BigInt() *big.Int {
|
||||
|
||||
// Public returns the PublicKey from the PrivateKey
|
||||
func (sk *PrivateKey) Public() *PublicKey {
|
||||
Q := G.Mul(sk.BigInt())
|
||||
pk := PublicKey(*Q)
|
||||
q := G.Mul(sk.BigInt())
|
||||
pk := PublicKey(*q)
|
||||
return &pk
|
||||
}
|
||||
|
||||
@@ -188,13 +183,26 @@ func (pk *PublicKey) Point() *Point {
|
||||
}
|
||||
|
||||
// NewRequestParameters returns a new random k (secret) & R (public) parameters
|
||||
func NewRequestParameters() (*big.Int, *Point) {
|
||||
k := newRand()
|
||||
return k, G.Mul(k) // R = kG
|
||||
func NewRequestParameters() (*big.Int, *Point, error) {
|
||||
k, err := newRand()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// k, R = kG
|
||||
return k, G.Mul(k), nil
|
||||
}
|
||||
|
||||
func checkBigIntSize(b *big.Int) error {
|
||||
// check b.Bytes()==32, as go returns big-endian representation of the
|
||||
// bigint, so if length is not 32 we have a smaller value than expected
|
||||
if len(b.Bytes()) != 32 { //nolint:gomnd
|
||||
return fmt.Errorf("invalid length, need 32 bytes")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BlindSign performs the blind signature on the given mBlinded using the
|
||||
// PrivateKey and the secret k values
|
||||
// PrivateKey and the secret k values.
|
||||
func (sk *PrivateKey) BlindSign(mBlinded *big.Int, k *big.Int) (*big.Int, error) {
|
||||
// TODO add pending checks
|
||||
if mBlinded.Cmp(N) != -1 {
|
||||
@@ -203,10 +211,12 @@ func (sk *PrivateKey) BlindSign(mBlinded *big.Int, k *big.Int) (*big.Int, error)
|
||||
if bytes.Equal(mBlinded.Bytes(), big.NewInt(0).Bytes()) {
|
||||
return nil, fmt.Errorf("mBlinded can not be 0")
|
||||
}
|
||||
// TMP
|
||||
// if mBlinded.BitLen() < MinBigIntBytesLen {
|
||||
// return nil, fmt.Errorf("mBlinded too small")
|
||||
// }
|
||||
if err := checkBigIntSize(mBlinded); err != nil {
|
||||
return nil, fmt.Errorf("mBlinded error: %s", err)
|
||||
}
|
||||
if err := checkBigIntSize(k); err != nil {
|
||||
return nil, fmt.Errorf("k error: %s", err)
|
||||
}
|
||||
|
||||
// s' = dm' + k
|
||||
sBlind := new(big.Int).Add(
|
||||
@@ -231,16 +241,22 @@ func Blind(m *big.Int, signerR *Point) (*big.Int, *UserSecretData, error) {
|
||||
return nil, nil, fmt.Errorf("signerR %s", err)
|
||||
}
|
||||
|
||||
var err error
|
||||
u := &UserSecretData{}
|
||||
u.A = newRand()
|
||||
u.B = newRand()
|
||||
u.A, err = newRand()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u.B, err = newRand()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// (R) F = aR' + bG
|
||||
aR := signerR.Mul(u.A)
|
||||
bG := G.Mul(u.B)
|
||||
u.F = aR.Add(bG)
|
||||
|
||||
// TODO check that F != O (point at infinity)
|
||||
if err := u.F.isValid(); err != nil {
|
||||
return nil, nil, fmt.Errorf("u.F %s", err)
|
||||
}
|
||||
@@ -319,8 +335,10 @@ func Verify(m *big.Int, s *Signature, q *PublicKey) bool {
|
||||
|
||||
rx := new(big.Int).Mod(s.F.X, N)
|
||||
rxh := new(big.Int).Mul(rx, h)
|
||||
// do mod, as go-ethereum/crypto/secp256k1 can not handle scalars > 256 bits
|
||||
rxhMod := new(big.Int).Mod(rxh, N)
|
||||
// rxhG := G.Mul(rxh) // originally the paper uses G
|
||||
rxhG := q.Point().Mul(rxh)
|
||||
rxhG := q.Point().Mul(rxhMod)
|
||||
|
||||
right := s.F.Add(rxhG)
|
||||
|
||||
|
||||
@@ -12,15 +12,18 @@ import (
|
||||
|
||||
func TestFlow(t *testing.T) {
|
||||
// signer: create new signer key pair
|
||||
sk := NewPrivateKey()
|
||||
sk, err := NewPrivateKey()
|
||||
require.Nil(t, err)
|
||||
signerPubK := sk.Public()
|
||||
|
||||
// signer: when user requests new R parameter to blind a new msg,
|
||||
// create new signerR (public) with its secret k
|
||||
k, signerR := NewRequestParameters()
|
||||
k, signerR, err := NewRequestParameters()
|
||||
require.Nil(t, err)
|
||||
|
||||
// user: blinds the msg using signer's R
|
||||
msg := new(big.Int).SetBytes([]byte("test"))
|
||||
// msg := new(big.Int).SetBytes([]byte("test"))
|
||||
msg := new(big.Int).SetBytes(crypto.Keccak256([]byte("test")))
|
||||
msgBlinded, userSecretData, err := Blind(msg, signerR)
|
||||
require.Nil(t, err)
|
||||
|
||||
@@ -40,6 +43,18 @@ func TestFlow(t *testing.T) {
|
||||
assert.True(t, verified)
|
||||
}
|
||||
|
||||
func TestSmallBlindedMsg(t *testing.T) {
|
||||
sk, err := NewPrivateKey()
|
||||
require.Nil(t, err)
|
||||
k := big.NewInt(1)
|
||||
smallMsgBlinded := big.NewInt(1)
|
||||
|
||||
// try to BlindSign a small value
|
||||
_, err = sk.BlindSign(smallMsgBlinded, k)
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, "mBlinded error: invalid length, need 32 bytes", err.Error())
|
||||
}
|
||||
|
||||
func TestHashMOddBytes(t *testing.T) {
|
||||
// This test is made with same values than
|
||||
// https://github.com/arnaucube/blindsecp256k1-js to ensure
|
||||
@@ -122,7 +137,11 @@ func TestSignatureCompressDecompress(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, sig, sig2)
|
||||
|
||||
// Q = (P+1)/4
|
||||
Q := new(big.Int).Div(new(big.Int).Add(P,
|
||||
big.NewInt(1)), big.NewInt(4)) // nolint:gomnd
|
||||
f = G
|
||||
|
||||
sig = &Signature{
|
||||
S: Q,
|
||||
F: f,
|
||||
|
||||
1
go.mod
1
go.mod
@@ -3,7 +3,6 @@ module github.com/arnaucube/go-blindsecp256k1
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6
|
||||
github.com/ethereum/go-ethereum v1.9.25
|
||||
github.com/stretchr/testify v1.6.1
|
||||
)
|
||||
|
||||
4
go.sum
4
go.sum
@@ -80,8 +80,10 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht
|
||||
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
@@ -169,6 +171,7 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8 h1:AvbQYmiaaaza3cW3QXRyPo5kYgpFIzOAfeAAN7m3qQ4=
|
||||
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
@@ -190,6 +193,7 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
|
||||
|
||||
@@ -11,31 +11,34 @@ package blindsecp256k1v0
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"math/big"
|
||||
|
||||
"github.com/arnaucube/go-blindsecp256k1"
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
)
|
||||
|
||||
// WIP
|
||||
func newRand() *big.Int {
|
||||
var b [32]byte
|
||||
_, err := rand.Read(b[:])
|
||||
func newRand() (*big.Int, error) {
|
||||
pk, err := ecdsa.GenerateKey(secp256k1.S256(), rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
bi := new(big.Int).SetBytes(b[:])
|
||||
return new(big.Int).Mod(bi, blindsecp256k1.N)
|
||||
return pk.D, nil
|
||||
}
|
||||
|
||||
// PrivateKey represents the signer's private key
|
||||
type PrivateKey big.Int
|
||||
|
||||
// NewPrivateKey returns a new random private key
|
||||
func NewPrivateKey() *PrivateKey {
|
||||
k := newRand()
|
||||
func NewPrivateKey() (*PrivateKey, error) {
|
||||
k, err := newRand()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sk := PrivateKey(*k)
|
||||
return &sk
|
||||
return &sk, nil
|
||||
}
|
||||
|
||||
// BigInt returns a *big.Int representation of the PrivateKey
|
||||
@@ -51,14 +54,20 @@ func (sk *PrivateKey) Public() *blindsecp256k1.PublicKey {
|
||||
}
|
||||
|
||||
// NewRequestParameters returns a new random k (secret) & R (public) parameters
|
||||
func NewRequestParameters() (*big.Int, *blindsecp256k1.Point) {
|
||||
k := newRand()
|
||||
return k, blindsecp256k1.G.Mul(k) // R = kG
|
||||
func NewRequestParameters() (*big.Int, *blindsecp256k1.Point, error) {
|
||||
k, err := newRand()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// k, R = kG
|
||||
return k, blindsecp256k1.G.Mul(k), nil
|
||||
}
|
||||
|
||||
// BlindSign performs the blind signature on the given mBlinded using
|
||||
// SignerPrivateData values
|
||||
func (sk *PrivateKey) BlindSign(mBlinded *big.Int, k *big.Int) *big.Int {
|
||||
// WARNING missing checks, this package is not updated, use
|
||||
// blindsecp256k1 instead
|
||||
// TODO add pending checks
|
||||
// s' = d(m') + k
|
||||
sBlind := new(big.Int).Add(
|
||||
@@ -79,11 +88,21 @@ type UserSecretData struct {
|
||||
|
||||
// Blind performs the blinding operation on m using SignerPublicData parameters
|
||||
func Blind(m *big.Int, signerPubK *blindsecp256k1.PublicKey,
|
||||
signerR *blindsecp256k1.Point) (*big.Int, *UserSecretData) {
|
||||
signerR *blindsecp256k1.Point) (*big.Int, *UserSecretData, error) {
|
||||
var err error
|
||||
u := &UserSecretData{}
|
||||
u.A = newRand()
|
||||
u.B = newRand()
|
||||
u.C = newRand()
|
||||
u.A, err = newRand()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u.B, err = newRand()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u.C, err = newRand()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
binv := new(big.Int).ModInverse(u.B, blindsecp256k1.N)
|
||||
|
||||
// F = b^-1 R + a b^-1 Q + c G
|
||||
@@ -102,7 +121,7 @@ func Blind(m *big.Int, signerPubK *blindsecp256k1.PublicKey,
|
||||
brm := new(big.Int).Mul(br, m)
|
||||
mBlinded := new(big.Int).Add(brm, u.A)
|
||||
mBlinded = new(big.Int).Mod(mBlinded, blindsecp256k1.N)
|
||||
return mBlinded, u
|
||||
return mBlinded, u, nil
|
||||
}
|
||||
|
||||
// Signature contains the signature values S & F
|
||||
|
||||
@@ -5,20 +5,24 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFlow(t *testing.T) {
|
||||
// signer: create new signer key pair
|
||||
sk := NewPrivateKey()
|
||||
sk, err := NewPrivateKey()
|
||||
require.Nil(t, err)
|
||||
signerPubK := sk.Public()
|
||||
|
||||
// signer: when user requests new R parameter to blind a new msg,
|
||||
// create new signerR (public) with its secret k
|
||||
k, signerR := NewRequestParameters()
|
||||
k, signerR, err := NewRequestParameters()
|
||||
require.Nil(t, err)
|
||||
|
||||
// user: blinds the msg using signer's R
|
||||
msg := new(big.Int).SetBytes([]byte("test"))
|
||||
msgBlinded, userSecretData := Blind(msg, signerPubK, signerR)
|
||||
msgBlinded, userSecretData, err := Blind(msg, signerPubK, signerR)
|
||||
require.Nil(t, err)
|
||||
|
||||
// signer: signs the blinded message using its private key & secret k
|
||||
sBlind := sk.BlindSign(msgBlinded, k)
|
||||
|
||||
@@ -66,7 +66,10 @@ func blindv0(this js.Value, values []js.Value) interface{} {
|
||||
Y: signerRy,
|
||||
}
|
||||
|
||||
mBlinded, user := blindsecp256k1v0.Blind(m, signerQ, signerR)
|
||||
mBlinded, user, err := blindsecp256k1v0.Blind(m, signerQ, signerR)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
r := make(map[string]interface{})
|
||||
r["mBlinded"] = mBlinded.String()
|
||||
|
||||
Reference in New Issue
Block a user