diff --git a/README.md b/README.md index a0e8d05..c1bdd96 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,15 @@ k, signerR := NewRequestParameters() // user: blinds the msg using signer's R msg := new(big.Int).SetBytes([]byte("test")) -msgBlinded, userSecretData := Blind(msg, signerR) +msgBlinded, userSecretData, err := Blind(msg, signerR) +require.Nil(t, err) // signer: signs the blinded message using its private key & secret k -sBlind := sk.BlindSign(msgBlinded, k) +sBlind, err := sk.BlindSign(msgBlinded, k) +require.Nil(t, err) // user: unblinds the blinded signature -sig := Unblind(sBlind, msg, userSecretData) +sig := Unblind(sBlind, userSecretData) // signature can be verified with signer PublicKey verified := Verify(msg, sig, signerPubK) diff --git a/blindsecp256k1.go b/blindsecp256k1.go index 177d5d6..78f2219 100644 --- a/blindsecp256k1.go +++ b/blindsecp256k1.go @@ -12,12 +12,20 @@ package blindsecp256k1 import ( "bytes" "crypto/rand" + "fmt" "math/big" "github.com/btcsuite/btcd/btcec" "github.com/ethereum/go-ethereum/crypto" ) +// TMP +// const ( +// // MinBigIntBytesLen defines the minimum bytes length of the minimum +// // accepted value for the checked *big.Int +// MinBigIntBytesLen = 20 * 8 +// ) + var ( // G represents the base point of secp256k1 G *Point = &Point{ @@ -27,6 +35,8 @@ var ( // N represents the order of G of secp256k1 N *big.Int = btcec.S256().N + + zero *big.Int = big.NewInt(0) ) // Point represents a point on the secp256k1 curve @@ -53,6 +63,19 @@ func (p *Point) Mul(scalar *big.Int) *Point { } } +func (p *Point) isValid() error { + if !btcec.S256().IsOnCurve(p.X, p.Y) { + return fmt.Errorf("Point is not on secp256k1") + } + + if bytes.Equal(p.X.Bytes(), zero.Bytes()) && + bytes.Equal(p.Y.Bytes(), zero.Bytes()) { + return fmt.Errorf("Point (%s, %s) can not be (0, 0)", + p.X.String(), p.Y.String()) + } + return nil +} + // WIP func newRand() *big.Int { var b [32]byte @@ -102,27 +125,42 @@ func NewRequestParameters() (*big.Int, *Point) { // BlindSign performs the blind signature on the given mBlinded using the // PrivateKey and the secret k values -func (sk *PrivateKey) BlindSign(mBlinded *big.Int, k *big.Int) *big.Int { +func (sk *PrivateKey) BlindSign(mBlinded *big.Int, k *big.Int) (*big.Int, error) { // TODO add pending checks + if mBlinded.Cmp(N) != -1 { + return nil, fmt.Errorf("mBlinded not inside the finite field") + } + 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") + // } + // s' = dm' + k sBlind := new(big.Int).Add( new(big.Int).Mul(sk.BigInt(), mBlinded), k) sBlind = new(big.Int).Mod(sBlind, N) - return sBlind + return sBlind, nil } -// UserSecretData contains the secret values from the User (a, b, c) and the +// UserSecretData contains the secret values from the User (a, b) and the // public F type UserSecretData struct { A *big.Int B *big.Int - F *Point // public (in the paper is R) + F *Point // public (in the paper is named R) } // Blind performs the blinding operation on m using signerR parameter -func Blind(m *big.Int, signerR *Point) (*big.Int, *UserSecretData) { +func Blind(m *big.Int, signerR *Point) (*big.Int, *UserSecretData, error) { + if !btcec.S256().IsOnCurve(signerR.X, signerR.Y) { + return nil, nil, fmt.Errorf("signerR point is not on secp256k1") + } + u := &UserSecretData{} u.A = newRand() u.B = newRand() @@ -133,6 +171,9 @@ func Blind(m *big.Int, signerR *Point) (*big.Int, *UserSecretData) { u.F = aR.Add(bG) // TODO check that F != O (point at infinity) + if err := u.F.isValid(); err != nil { + return nil, nil, err + } rx := new(big.Int).Mod(u.F.X, N) @@ -144,7 +185,7 @@ func Blind(m *big.Int, signerR *Point) (*big.Int, *UserSecretData) { mBlinded := new(big.Int).Mul(ainvrx, h) mBlinded = new(big.Int).Mod(mBlinded, N) - return mBlinded, u + return mBlinded, u, nil } // Signature contains the signature values S & F @@ -170,6 +211,12 @@ func Unblind(sBlind *big.Int, u *UserSecretData) *Signature { // Verify checks the signature of the message m for the given PublicKey func Verify(m *big.Int, s *Signature, q *PublicKey) bool { // TODO add pending checks + if err := s.F.isValid(); err != nil { + return false + } + if err := q.Point().isValid(); err != nil { + return false + } sG := G.Mul(s.S) // sG diff --git a/blindsecp256k1_test.go b/blindsecp256k1_test.go index 1c0e7af..fa9837d 100644 --- a/blindsecp256k1_test.go +++ b/blindsecp256k1_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestFlow(t *testing.T) { @@ -18,10 +19,12 @@ func TestFlow(t *testing.T) { // user: blinds the msg using signer's R msg := new(big.Int).SetBytes([]byte("test")) - msgBlinded, userSecretData := Blind(msg, signerR) + msgBlinded, userSecretData, err := Blind(msg, signerR) + require.Nil(t, err) // signer: signs the blinded message using its private key & secret k - sBlind := sk.BlindSign(msgBlinded, k) + sBlind, err := sk.BlindSign(msgBlinded, k) + require.Nil(t, err) // user: unblinds the blinded signature sig := Unblind(sBlind, userSecretData) @@ -34,3 +37,27 @@ func TestFlow(t *testing.T) { verified := Verify(msg, sig, signerPubK) assert.True(t, verified) } + +// func newBigIntWithBitLen(n int) *big.Int { +// b := make([]byte, n/8) +// for i := 0; i < len(b); i++ { +// b[i] = 255 +// } +// bi := new(big.Int).SetBytes(b[:]) +// return bi +// } +// +// func TestMinBigIntBytesLen(t *testing.T) { +// k := big.NewInt(1) +// sk := PrivateKey(*k) +// +// mBlinded := newBigIntWithBitLen(MinBigIntBytesLen) +// require.Equal(t, MinBigIntBytesLen, mBlinded.BitLen()) +// _, err := sk.BlindSign(mBlinded, k) +// assert.Nil(t, err) +// +// mBlinded = new(big.Int).Div(mBlinded, big.NewInt(2)) +// require.Equal(t, MinBigIntBytesLen-1, mBlinded.BitLen()) +// _, err = sk.BlindSign(mBlinded, k) +// assert.Equal(t, "mBlinded too small", err.Error()) +// } diff --git a/wasm/blindsecp256k1-wasm.go b/wasm/blindsecp256k1-wasm.go index 8d88e4d..92e301f 100644 --- a/wasm/blindsecp256k1-wasm.go +++ b/wasm/blindsecp256k1-wasm.go @@ -159,7 +159,10 @@ func blind(this js.Value, values []js.Value) interface{} { Y: signerRy, } - mBlinded, user := blindsecp256k1.Blind(m, signerR) + mBlinded, user, err := blindsecp256k1.Blind(m, signerR) + if err != nil { + panic(err) + } r := make(map[string]interface{}) r["mBlinded"] = mBlinded.String() diff --git a/wasm/webtest/blindsecp256k1.wasm b/wasm/webtest/blindsecp256k1.wasm index 0bbe52a..a86b146 100755 Binary files a/wasm/webtest/blindsecp256k1.wasm and b/wasm/webtest/blindsecp256k1.wasm differ