arnaucube
arnaucube/go-blindsecp256k1Public Self-hosted repository
Add checks to inputs at Blind & BlindSign
arnaucube root@arnaucube.com
Mon, 08 Feb 2021 23:05:21 +0100
commit

ac5d00b89229c8edcaa5e31cc62470fe74c32f37

parent

876755a714c34752a8572de02198d0c934cc2027

M README.md → 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)
M blindsecp256k1.go → blindsecp256k1.go

@@ -12,11 +12,19 @@

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

@@ -27,6 +35,8 @@ }

// 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 @@ Y: y,

} } +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 @@ }

// 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 @@ 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, err + } rx := new(big.Int).Mod(u.F.X, N)

@@ -144,7 +185,7 @@ h := new(big.Int).SetBytes(hBytes)

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 @@

// 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
M blindsecp256k1_test.go → blindsecp256k1_test.go

@@ -5,6 +5,7 @@ "math/big"

"testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestFlow(t *testing.T) {

@@ -18,10 +19,12 @@ 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, userSecretData)

@@ -34,3 +37,27 @@ // signature can be verified with signer PublicKey

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()) +// }
M wasm/blindsecp256k1-wasm.go → wasm/blindsecp256k1-wasm.go

@@ -159,7 +159,10 @@ X: signerRx,

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()