diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index cdedb10..0e2fc88 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,4 +13,5 @@ jobs: - name: Lint run: | curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.30.0 + rm -r wasm $(go env GOPATH)/bin/golangci-lint run --timeout=5m -c .golangci.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 045c0ba..084d1e6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,4 +16,4 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Run tests - run: go test ./... + run: go test $(go list ./... | grep -v /wasm) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..14fe915 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +wasm_exec.js diff --git a/README.md b/README.md index a6ddaca..9b2869b 100644 --- a/README.md +++ b/README.md @@ -27,3 +27,6 @@ sig := blindsecp256k1.Unblind(sBlind, msg, user) verified := blindsecp256k1.Verify(msg, sig, signerPublicData.Q) assert.True(t, verified) ``` + +## 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. diff --git a/wasm/README.md b/wasm/README.md new file mode 100644 index 0000000..2f511e8 --- /dev/null +++ b/wasm/README.md @@ -0,0 +1,15 @@ +# blindsecp256k1 wasm clientlib +[blindsecp256k1](https://github.com/arnaucube/go-blindsecp256k1) lib for browsers using go WASM. + +## Wasm usage +To compile to wasm, inside the `wasm` directory, execute: +``` +./build.sh +``` + +Add the file `wasm_exec.js` in the `webtest` directory: +``` +cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" . +``` + +To see the usage from javascript, check `index.js` file. diff --git a/wasm/blindsecp256k1-wasm.go b/wasm/blindsecp256k1-wasm.go new file mode 100644 index 0000000..5dad320 --- /dev/null +++ b/wasm/blindsecp256k1-wasm.go @@ -0,0 +1,100 @@ +package main + +import ( + "blindsecp256k1" + "fmt" + "math/big" + "syscall/js" +) + +func main() { + c := make(chan struct{}, 0) + println("WASM blindsecp256k1 initialized") + registerCallbacks() + <-c +} + +func registerCallbacks() { + js.Global().Set("blind", js.FuncOf(blind)) + js.Global().Set("unblind", js.FuncOf(unblind)) +} + +func stringToBigInt(s string) *big.Int { + b, ok := new(big.Int).SetString(s, 10) + if !ok { + panic(fmt.Errorf("error parsing string *big.Int: %s", s)) + } + return b +} + +func blind(this js.Value, values []js.Value) interface{} { + mStr := values[0].String() + signerQxStr := values[1].String() + signerQyStr := values[2].String() + signerRxStr := values[3].String() + signerRyStr := values[4].String() + + m := stringToBigInt(mStr) + signerQx := stringToBigInt(signerQxStr) + signerQy := stringToBigInt(signerQyStr) + signerRx := stringToBigInt(signerRxStr) + signerRy := stringToBigInt(signerRyStr) + + signerQ := &blindsecp256k1.PublicKey{ + X: signerQx, + Y: signerQy, + } + signerR := &blindsecp256k1.Point{ + X: signerRx, + Y: signerRy, + } + + signer := &blindsecp256k1.SignerPublicData{signerQ, signerR} + mBlinded, user := blindsecp256k1.Blind(m, signer) + + r := make(map[string]interface{}) + r["mBlinded"] = mBlinded.String() + r["uA"] = user.A.String() + r["uB"] = user.B.String() + r["uC"] = user.C.String() + r["uC"] = user.C.String() + r["uFx"] = user.F.X.String() + r["uFy"] = user.F.Y.String() + return r +} + +func unblind(this js.Value, values []js.Value) interface{} { + sBlindStr := values[0].String() + mStr := values[1].String() + uBStr := values[2].String() + uCStr := values[3].String() + uFxStr := values[4].String() + uFyStr := values[5].String() + + sBlind := stringToBigInt(sBlindStr) + m := stringToBigInt(mStr) + uB := stringToBigInt(uBStr) + uC := stringToBigInt(uCStr) + uFx := stringToBigInt(uFxStr) + uFy := stringToBigInt(uFyStr) + + uF := &blindsecp256k1.Point{ + X: uFx, + Y: uFy, + } + + u := &blindsecp256k1.UserSecretData{ + // A not needed to Unblind + B: uB, + C: uC, + F: uF, + } + + sig := blindsecp256k1.Unblind(sBlind, m, u) + + r := make(map[string]interface{}) + r["s"] = sig.S.String() + r["fx"] = sig.F.X.String() + r["fy"] = sig.F.Y.String() + return r +} diff --git a/wasm/build.sh b/wasm/build.sh new file mode 100755 index 0000000..b720a9f --- /dev/null +++ b/wasm/build.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +GOARCH=wasm GOOS=js go build -o blindsecp256k1.wasm blindsecp256k1-wasm.go +mv blindsecp256k1.wasm webtest/blindsecp256k1.wasm diff --git a/wasm/webtest/blindsecp256k1.wasm b/wasm/webtest/blindsecp256k1.wasm new file mode 100755 index 0000000..9e033aa Binary files /dev/null and b/wasm/webtest/blindsecp256k1.wasm differ diff --git a/wasm/webtest/index.html b/wasm/webtest/index.html new file mode 100644 index 0000000..8b5b9a6 --- /dev/null +++ b/wasm/webtest/index.html @@ -0,0 +1,18 @@ + + + + blindsecp256k1 WASM wrappers + + + + +

Open the browser console to see the logs

+ + + + diff --git a/wasm/webtest/index.js b/wasm/webtest/index.js new file mode 100644 index 0000000..ebe1960 --- /dev/null +++ b/wasm/webtest/index.js @@ -0,0 +1,16 @@ +function test() { + let m = "1952805748"; + + // Q & R would be received from the Signer + let signerQx = "26613296432153871833441195158297038913673464785502568519907582377915678491093"; + let signerQy = "81940194042971427014176158889809922552127995083760111384335138546589994227275"; + let signerRx = "59371873487402651110657306418818354906476102545298559461791300717696053835454"; + let signerRy = "98322875246066710654579302898391677189379767946198239290895789444110962324342"; + let blindRes = blind(m, signerQx, signerQy, signerRx, signerRy); + console.log("blind", blindRes); + + // sBlind would be received from the Signer + let sBlind = "7240298625621589352655632414257224668430424461224914067754717095121139699933353374227084479180038954015287518505167995306229258561275087198611946596619855"; + let unblindRes = unblind(sBlind, m, blindRes.uB, blindRes.uC, blindRes.uFx, blindRes.uFy); + console.log("unblind", unblindRes); +}