diff --git a/blindsecp256k1.go b/blindsecp256k1.go index 9ec7c0d..40c25d4 100644 --- a/blindsecp256k1.go +++ b/blindsecp256k1.go @@ -12,6 +12,8 @@ package blindsecp256k1 import ( "bytes" "crypto/rand" + "encoding/json" + "fmt" "math/big" "github.com/btcsuite/btcd/btcec" @@ -53,6 +55,40 @@ func (p *Point) Mul(scalar *big.Int) *Point { } } +// MarshalJSON implements the json marshaler for the Point +func (p Point) MarshalJSON() ([]byte, error) { + return json.Marshal(&struct { + X string `json:"x"` + Y string `json:"y"` + }{ + X: p.X.String(), + Y: p.Y.String(), + }) +} + +// UnmarshalJSON implements the json unmarshaler for the Point +func (p *Point) UnmarshalJSON(b []byte) error { + aux := &struct { + X string `json:"x"` + Y string `json:"y"` + }{} + err := json.Unmarshal(b, &aux) + if err != nil { + return err + } + x, ok := new(big.Int).SetString(aux.X, 10) + if !ok { + return fmt.Errorf("Can not parse Point.X %s", aux.X) + } + y, ok := new(big.Int).SetString(aux.Y, 10) + if !ok { + return fmt.Errorf("Can not parse Point.Y %s", aux.Y) + } + p.X = x + p.Y = y + return nil +} + // WIP func newRand() *big.Int { var b [32]byte @@ -70,6 +106,23 @@ type PrivateKey big.Int // PublicKey represents the signer's public key type PublicKey Point +// MarshalJSON implements the json marshaler for the PublicKey +func (pk PublicKey) MarshalJSON() ([]byte, error) { + return json.Marshal(pk.Point()) +} + +// UnmarshalJSON implements the json unmarshaler for the PublicKey +func (pk *PublicKey) UnmarshalJSON(b []byte) error { + var point *Point + err := json.Unmarshal(b, &point) + if err != nil { + return err + } + pk.X = point.X + pk.Y = point.Y + return nil +} + // NewPrivateKey returns a new random private key func NewPrivateKey() *PrivateKey { k := newRand() @@ -151,6 +204,60 @@ type Signature struct { F *Point } +// MarshalJSON implements the json marshaler for the Signature +func (sig Signature) MarshalJSON() ([]byte, error) { + return json.Marshal(&struct { + S string `json:"s"` + F struct { + X string `json:"x"` + Y string `json:"y"` + } `json:"f"` + }{ + S: sig.S.String(), + F: struct { + X string `json:"x"` + Y string `json:"y"` + }{ + X: sig.F.X.String(), + Y: sig.F.Y.String(), + }, + }) +} + +// UnmarshalJSON implements the json unmarshaler for the Signature +func (sig *Signature) UnmarshalJSON(b []byte) error { + aux := &struct { + S string `json:"s"` + F struct { + X string `json:"x"` + Y string `json:"y"` + } `json:"f"` + }{} + err := json.Unmarshal(b, &aux) + if err != nil { + return err + } + + s, ok := new(big.Int).SetString(aux.S, 10) + if !ok { + return fmt.Errorf("Can not parse sig.S %s", aux.S) + } + sig.S = s + + x, ok := new(big.Int).SetString(aux.F.X, 10) + if !ok { + return fmt.Errorf("Can not parse sig.F.X %s", aux.F.X) + } + y, ok := new(big.Int).SetString(aux.F.Y, 10) + if !ok { + return fmt.Errorf("Can not parse sig.F.Y %s", aux.F.Y) + } + sig.F = &Point{} + sig.F.X = x + sig.F.Y = y + return nil +} + // Unblind performs the unblinding operation of the blinded signature for the // given message m and the UserSecretData func Unblind(sBlind, m *big.Int, u *UserSecretData) *Signature { @@ -165,19 +272,20 @@ func Unblind(sBlind, m *big.Int, u *UserSecretData) *Signature { } // Verify checks the signature of the message m for the given PublicKey -func Verify(m *big.Int, signature *Signature, q *PublicKey) bool { +func Verify(m *big.Int, s *Signature, q *PublicKey) bool { // TODO add pending checks - sG := G.Mul(signature.S) // sG + + sG := G.Mul(s.S) // sG hBytes := crypto.Keccak256(m.Bytes()) h := new(big.Int).SetBytes(hBytes) - rx := new(big.Int).Mod(signature.F.X, N) + rx := new(big.Int).Mod(s.F.X, N) rxh := new(big.Int).Mul(rx, h) // rxhG := G.Mul(rxh) // originally the paper uses G rxhG := q.Point().Mul(rxh) - right := signature.F.Add(rxhG) + right := s.F.Add(rxhG) // check sG == R + rx h(m) G (where R in this code is F) if bytes.Equal(sG.X.Bytes(), right.X.Bytes()) && diff --git a/blindsecp256k1_test.go b/blindsecp256k1_test.go index 6175d36..65ac5ff 100644 --- a/blindsecp256k1_test.go +++ b/blindsecp256k1_test.go @@ -1,10 +1,12 @@ package blindsecp256k1 import ( + "encoding/json" "math/big" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestFlow(t *testing.T) { @@ -30,3 +32,47 @@ func TestFlow(t *testing.T) { verified := Verify(msg, sig, signerPubK) assert.True(t, verified) } + +func TestMarshalers(t *testing.T) { + // Point + p := G.Mul(big.NewInt(1234)) + b, err := json.Marshal(p) + require.Nil(t, err) + assert.Equal(t, + `{"x":"102884003323827292915668239759940053105992008087520207150474896054185180420338","y":"49384988101491619794462775601349526588349137780292274540231125201115197157452"}`, //nolint:lll + string(b)) + + var p2 *Point + err = json.Unmarshal(b, &p2) + require.Nil(t, err) + assert.Equal(t, p, p2) + + // PublicKey + pk := PublicKey(*p) + b, err = json.Marshal(pk) + require.Nil(t, err) + assert.Equal(t, + `{"x":"102884003323827292915668239759940053105992008087520207150474896054185180420338","y":"49384988101491619794462775601349526588349137780292274540231125201115197157452"}`, //nolint:lll + string(b)) + + var pk2 PublicKey + err = json.Unmarshal(b, &pk2) + require.Nil(t, err) + assert.Equal(t, pk, pk2) + + // Signature + sig := Signature{ + S: big.NewInt(9876), + F: p, + } + b, err = json.Marshal(sig) + require.Nil(t, err) + assert.Equal(t, + `{"s":"9876","f":{"x":"102884003323827292915668239759940053105992008087520207150474896054185180420338","y":"49384988101491619794462775601349526588349137780292274540231125201115197157452"}}`, //nolint:lll + string(b)) + + var sig2 Signature + err = json.Unmarshal(b, &sig2) + require.Nil(t, err) + assert.Equal(t, sig, sig2) +} diff --git a/v0/blindsecp256k1v0.go b/v0/blindsecp256k1v0.go index 1308f1e..eeba5fb 100644 --- a/v0/blindsecp256k1v0.go +++ b/v0/blindsecp256k1v0.go @@ -14,44 +14,9 @@ import ( "crypto/rand" "math/big" - "github.com/btcsuite/btcd/btcec" + "github.com/arnaucube/go-blindsecp256k1" ) -var ( - // G represents the base point of secp256k1 - G *Point = &Point{ - X: btcec.S256().Gx, - Y: btcec.S256().Gy, - } - - // N represents the order of G of secp256k1 - N *big.Int = btcec.S256().N -) - -// Point represents a point on the secp256k1 curve -type Point struct { - X *big.Int - Y *big.Int -} - -// 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) - return &Point{ - X: x, - Y: y, - } -} - -// 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()) - return &Point{ - X: x, - Y: y, - } -} - // WIP func newRand() *big.Int { var b [32]byte @@ -60,15 +25,12 @@ func newRand() *big.Int { panic(err) } bi := new(big.Int).SetBytes(b[:]) - return new(big.Int).Mod(bi, N) + return new(big.Int).Mod(bi, blindsecp256k1.N) } // PrivateKey represents the signer's private key type PrivateKey big.Int -// PublicKey represents the signer's public key -type PublicKey Point - // NewPrivateKey returns a new random private key func NewPrivateKey() *PrivateKey { k := newRand() @@ -82,21 +44,16 @@ 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) +func (sk *PrivateKey) Public() *blindsecp256k1.PublicKey { + Q := blindsecp256k1.G.Mul(sk.BigInt()) + pk := blindsecp256k1.PublicKey(*Q) return &pk } -// Point returns a *Point representation of the PublicKey -func (pk *PublicKey) Point() *Point { - return (*Point)(pk) -} - // NewRequestParameters returns a new random k (secret) & R (public) parameters -func NewRequestParameters() (*big.Int, *Point) { +func NewRequestParameters() (*big.Int, *blindsecp256k1.Point) { k := newRand() - return k, G.Mul(k) // R = kG + return k, blindsecp256k1.G.Mul(k) // R = kG } // BlindSign performs the blind signature on the given mBlinded using @@ -117,50 +74,51 @@ type UserSecretData struct { B *big.Int C *big.Int - F *Point // public + F *blindsecp256k1.Point // public } // Blind performs the blinding operation on m using SignerPublicData parameters -func Blind(m *big.Int, signerPubK *PublicKey, signerR *Point) (*big.Int, *UserSecretData) { +func Blind(m *big.Int, signerPubK *blindsecp256k1.PublicKey, + signerR *blindsecp256k1.Point) (*big.Int, *UserSecretData) { u := &UserSecretData{} u.A = newRand() u.B = newRand() u.C = newRand() - binv := new(big.Int).ModInverse(u.B, N) + binv := new(big.Int).ModInverse(u.B, blindsecp256k1.N) // F = b^-1 R + a b^-1 Q + c G bR := signerR.Mul(binv) abinv := new(big.Int).Mul(u.A, binv) - abinv = new(big.Int).Mod(abinv, N) + abinv = new(big.Int).Mod(abinv, blindsecp256k1.N) abQ := signerPubK.Point().Mul(abinv) - cG := G.Mul(u.C) + cG := blindsecp256k1.G.Mul(u.C) u.F = bR.Add(abQ).Add(cG) // TODO check F==O - r := new(big.Int).Mod(u.F.X, N) + r := new(big.Int).Mod(u.F.X, blindsecp256k1.N) // m' = br(m)+a br := new(big.Int).Mul(u.B, r) brm := new(big.Int).Mul(br, m) mBlinded := new(big.Int).Add(brm, u.A) - mBlinded = new(big.Int).Mod(mBlinded, N) + mBlinded = new(big.Int).Mod(mBlinded, blindsecp256k1.N) return mBlinded, u } // Signature contains the signature values S & F type Signature struct { S *big.Int - F *Point + F *blindsecp256k1.Point } // Unblind performs the unblinding operation of the blinded signature for the // given message m and the UserSecretData func Unblind(sBlind, m *big.Int, u *UserSecretData) *Signature { // s = b^-1 s' + c - binv := new(big.Int).ModInverse(u.B, N) + binv := new(big.Int).ModInverse(u.B, blindsecp256k1.N) bs := new(big.Int).Mul(binv, sBlind) s := new(big.Int).Add(bs, u.C) - s = new(big.Int).Mod(s, N) + s = new(big.Int).Mod(s, blindsecp256k1.N) return &Signature{ S: s, @@ -169,13 +127,13 @@ func Unblind(sBlind, m *big.Int, u *UserSecretData) *Signature { } // Verify checks the signature of the message m for the given PublicKey -func Verify(m *big.Int, signature *Signature, q *PublicKey) bool { +func Verify(m *big.Int, signature *Signature, q *blindsecp256k1.PublicKey) bool { // TODO add pending checks - sG := G.Mul(signature.S) // sG + sG := blindsecp256k1.G.Mul(signature.S) // sG - r := new(big.Int).Mod(signature.F.X, N) // r = Fx mod N + r := new(big.Int).Mod(signature.F.X, blindsecp256k1.N) // r = Fx mod N rm := new(big.Int).Mul(r, m) - rm = new(big.Int).Mod(rm, N) + rm = new(big.Int).Mod(rm, blindsecp256k1.N) rmQ := q.Point().Mul(rm) rmQF := rmQ.Add(signature.F) // rmQ + F diff --git a/wasm/blindsecp256k1-wasm.go b/wasm/blindsecp256k1-wasm.go index adf482e..cd42efa 100644 --- a/wasm/blindsecp256k1-wasm.go +++ b/wasm/blindsecp256k1-wasm.go @@ -1,12 +1,13 @@ package main import ( - "blindsecp256k1" "fmt" "math/big" "syscall/js" - blindsecp256k1v0 "blindsecp256k1/v0" + "github.com/arnaucube/go-blindsecp256k1" + + blindsecp256k1v0 "github.com/arnaucube/go-blindsecp256k1/v0" ) func main() { @@ -17,14 +18,18 @@ func main() { } func registerCallbacks() { + js.Global().Set("wasmReady", js.FuncOf(ready)) + // blindv0 & unblindv0 uses: // http://www.isecure-journal.com/article_39171_47f9ec605dd3918c2793565ec21fcd7a.pdf - js.Global().Set("blindv0", js.FuncOf(blindv0)) - js.Global().Set("unblindv0", js.FuncOf(unblindv0)) + js.Global().Set("wasmBlindv0", js.FuncOf(blindv0)) + js.Global().Set("wasmUnblindv0", js.FuncOf(unblindv0)) + js.Global().Set("wasmVerifyv0", js.FuncOf(verifyv0)) // blind & unblind uses: https://sci-hub.do/10.1109/ICCKE.2013.6682844 - js.Global().Set("blind", js.FuncOf(blind)) - js.Global().Set("unblind", js.FuncOf(unblind)) + js.Global().Set("wasmBlind", js.FuncOf(blind)) + js.Global().Set("wasmUnblind", js.FuncOf(unblind)) + js.Global().Set("wasmVerify", js.FuncOf(verify)) } func stringToBigInt(s string) *big.Int { @@ -35,6 +40,10 @@ func stringToBigInt(s string) *big.Int { return b } +func ready(this js.Value, values []js.Value) interface{} { + return "ready" +} + func blindv0(this js.Value, values []js.Value) interface{} { mStr := values[0].String() signerQxStr := values[1].String() @@ -48,11 +57,11 @@ func blindv0(this js.Value, values []js.Value) interface{} { signerRx := stringToBigInt(signerRxStr) signerRy := stringToBigInt(signerRyStr) - signerQ := &blindsecp256k1v0.PublicKey{ + signerQ := &blindsecp256k1.PublicKey{ X: signerQx, Y: signerQy, } - signerR := &blindsecp256k1v0.Point{ + signerR := &blindsecp256k1.Point{ X: signerRx, Y: signerRy, } @@ -85,7 +94,7 @@ func unblindv0(this js.Value, values []js.Value) interface{} { uFx := stringToBigInt(uFxStr) uFy := stringToBigInt(uFyStr) - uF := &blindsecp256k1v0.Point{ + uF := &blindsecp256k1.Point{ X: uFx, Y: uFy, } @@ -105,6 +114,39 @@ func unblindv0(this js.Value, values []js.Value) interface{} { r["fy"] = sig.F.Y.String() return r } + +func verifyv0(this js.Value, values []js.Value) interface{} { + mStr := values[0].String() + sigSStr := values[1].String() + sigFxStr := values[2].String() + sigFyStr := values[3].String() + qxStr := values[4].String() + qyStr := values[5].String() + + m := stringToBigInt(mStr) + sigS := stringToBigInt(sigSStr) + sigFx := stringToBigInt(sigFxStr) + sigFy := stringToBigInt(sigFyStr) + qx := stringToBigInt(qxStr) + qy := stringToBigInt(qyStr) + + q := &blindsecp256k1.PublicKey{ + X: qx, + Y: qy, + } + sig := &blindsecp256k1.Signature{ + S: sigS, + F: &blindsecp256k1.Point{ + X: sigFx, + Y: sigFy, + }, + } + verified := blindsecp256k1.Verify(m, sig, q) + + r := verified + return r +} + func blind(this js.Value, values []js.Value) interface{} { mStr := values[0].String() signerRxStr := values[1].String() @@ -164,3 +206,35 @@ func unblind(this js.Value, values []js.Value) interface{} { r["fy"] = sig.F.Y.String() return r } + +func verify(this js.Value, values []js.Value) interface{} { + mStr := values[0].String() + sigSStr := values[1].String() + sigFxStr := values[2].String() + sigFyStr := values[3].String() + qxStr := values[4].String() + qyStr := values[5].String() + + m := stringToBigInt(mStr) + sigS := stringToBigInt(sigSStr) + sigFx := stringToBigInt(sigFxStr) + sigFy := stringToBigInt(sigFyStr) + qx := stringToBigInt(qxStr) + qy := stringToBigInt(qyStr) + + q := &blindsecp256k1.PublicKey{ + X: qx, + Y: qy, + } + sig := &blindsecp256k1.Signature{ + S: sigS, + F: &blindsecp256k1.Point{ + X: sigFx, + Y: sigFy, + }, + } + verified := blindsecp256k1.Verify(m, sig, q) + + r := verified + return r +} diff --git a/wasm/webtest/blindsecp256k1.wasm b/wasm/webtest/blindsecp256k1.wasm index ca0f6b8..dad7eb6 100755 Binary files a/wasm/webtest/blindsecp256k1.wasm and b/wasm/webtest/blindsecp256k1.wasm differ diff --git a/wasm/webtest/index.js b/wasm/webtest/index.js index 77cd822..fe27c7d 100644 --- a/wasm/webtest/index.js +++ b/wasm/webtest/index.js @@ -3,25 +3,36 @@ function test() { console.log("using: https://sci-hub.do/10.1109/ICCKE.2013.6682844"); // R would be received from the Signer - let signerRx = "59371873487402651110657306418818354906476102545298559461791300717696053835454"; - let signerRy = "98322875246066710654579302898391677189379767946198239290895789444110962324342"; - let blindRes = blind(m, signerRx, signerRy); + let signerRx = "17814783168156809976981325336969869272256267559847863501362979416582031885685"; + let signerRy = "30466749656160766323378925376290982172805224557687141285291181575233995759897"; + let blindRes = wasmBlind(m, signerRx, signerRy); console.log("blind", blindRes); // Q & sBlind would be received from the Signer - let signerQx = "26613296432153871833441195158297038913673464785502568519907582377915678491093"; - let signerQy = "81940194042971427014176158889809922552127995083760111384335138546589994227275"; - let sBlind = "7240298625621589352655632414257224668430424461224914067754717095121139699933353374227084479180038954015287518505167995306229258561275087198611946596619855"; - let unblindRes = unblind(sBlind, m, blindRes.uA, blindRes.uB, blindRes.uFx, blindRes.uFy); + let signerQx = "91217724741799691300838336208439702708830781279546234509900618215893368170964"; + let signerQy = "10647409378909561143830454293907272341812664755625953321604115356883317910171"; + let sBlind = "1559989683738317700055715706344460781046571016142996697444777749433194958666958401306508176561868963591508234625762518936896506645022493420447764027537091595268073646775253821735958788229615883133396107736168033688269069669796190509031136746898237132145138091815479880246793211708356184248484212425679897377"; + let unblindRes = wasmUnblind(sBlind, m, blindRes.uA, blindRes.uB, blindRes.uFx, blindRes.uFy); console.log("unblind", unblindRes); + + // wasmVerify method not used here because the hardcoded values would + // not match with the random generated values from the 'blind' method + // let verified = wasmVerify(m, unblindRes.s, unblindRes.fx, unblindRes.fy, signerQx, signerQy); + // console.log("verify", verified); + // --- // v0 console.log("using: http://www.isecure-journal.com/article_39171_47f9ec605dd3918c2793565ec21fcd7a.pdf"); // Q & R would be received from the Signer - blindRes = blindv0(m, signerQx, signerQy, signerRx, signerRy); + blindRes = wasmBlindv0(m, signerQx, signerQy, signerRx, signerRy); console.log("blindv0", blindRes); // sBlind would be received from the Signer - unblindRes = unblindv0(sBlind, m, blindRes.uB, blindRes.uC, blindRes.uFx, blindRes.uFy); + unblindRes = wasmUnblindv0(sBlind, m, blindRes.uB, blindRes.uC, blindRes.uFx, blindRes.uFy); console.log("unblindv0", unblindRes); + + // wasmVerifyv0 method not used here because the hardcoded values would + // not match with the random generated values from the 'blind' method + // let verified = wasmVerifyv0(m, unblindRes.s, unblindRes.fx, unblindRes.fy, signerQx, signerQy); + // console.log("verify", verified); }