wasm proof generation from browser working. Added cli wasm exporters, html&js browser example, wasm wrapper from go

This commit is contained in:
arnaucube
2019-06-24 16:50:28 +02:00
parent 662d92b697
commit 0a162482ee
14 changed files with 260 additions and 6 deletions

View File

@@ -5,3 +5,6 @@ go:
env:
- GO111MODULE=on
before_install: rm wasm/go-snark-wasm-wrapper.go

View File

@@ -40,7 +40,11 @@ Improvements from the minimal implementation:
- [ ] move witness values calculation outside the setup phase
- [x] Groth16
- [ ] multiple optimizations
- [x] wasm proof generation
- [ ] wasm proof verification
## WASM usage
Ongoing experimentation with go-snark compiled to wasm: https://github.com/arnaucube/go-snark/tree/master/wasm
## Usage
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark?status.svg)](https://godoc.org/github.com/arnaucube/go-snark) zkSnark
@@ -87,6 +91,10 @@ In the command line, execute:
```
> ./go-snark-cli compile test.circuit
```
If you want to have the wasm input ready also, add the flag `wasm`
```
> ./go-snark-cli compile test.circuit wasm
```
This will output the `compiledcircuit.json` file.
@@ -97,6 +105,10 @@ Having the `compiledcircuit.json`, now we can generate the `TrustedSetup`:
```
This will create the file `trustedsetup.json` with the TrustedSetup data, and also a `toxic.json` file, with the parameters to delete from the `Trusted Setup`.
If you want to have the wasm input ready also, add the flag `wasm`
```
> ./go-snark-cli trustedsetup wasm
```
#### Generate Proofs
Assumming that we have the `compiledcircuit.json`, `trustedsetup.json`, `privateInputs.json` and the `publicInputs.json` we can now generate the `Proofs` with the following command:

View File

@@ -15,6 +15,7 @@ import (
"github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/groth16"
"github.com/arnaucube/go-snark/r1csqap"
"github.com/arnaucube/go-snark/wasm/utils"
"github.com/urfave/cli"
)
@@ -96,6 +97,11 @@ func CompileCircuit(context *cli.Context) error {
circuitPath := context.Args().Get(0)
wasmFlag := false
if context.Args().Get(1) == "wasm" {
wasmFlag = true
}
// read circuit file
circuitFile, err := os.Open(circuitPath)
panicErr(err)
@@ -185,10 +191,48 @@ func CompileCircuit(context *cli.Context) error {
jsonFile.Close()
fmt.Println("Compiled Circuit data written to ", jsonFile.Name())
if wasmFlag {
circuitString := utils.CircuitToString(*circuit)
jsonData, err := json.Marshal(circuitString)
panicErr(err)
// store setup into file
jsonFile, err := os.Create("compiledcircuitString.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
}
// store px
jsonData, err = json.Marshal(px)
panicErr(err)
// store setup into file
jsonFile, err = os.Create("px.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
fmt.Println("Px data written to ", jsonFile.Name())
if wasmFlag {
pxString := utils.ArrayBigIntToString(px)
jsonData, err = json.Marshal(pxString)
panicErr(err)
// store setup into file
jsonFile, err = os.Create("pxString.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
}
return nil
}
func TrustedSetup(context *cli.Context) error {
wasmFlag := false
if context.Args().Get(0) == "wasm" {
wasmFlag = true
}
// open compiledcircuit.json
compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
panicErr(err)
@@ -243,6 +287,17 @@ func TrustedSetup(context *cli.Context) error {
jsonFile.Write(jsonData)
jsonFile.Close()
fmt.Println("Trusted Setup data written to ", jsonFile.Name())
if wasmFlag {
tsetupString := utils.SetupToString(tsetup)
jsonData, err := json.Marshal(tsetupString)
panicErr(err)
// store setup into file
jsonFile, err := os.Create("trustedsetupString.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
}
return nil
}

Binary file not shown.

View File

@@ -24,20 +24,20 @@ type Setup struct {
// public
Pk struct { // Proving Key
BACDelta [][3]*big.Int // {( βui(x)+αvi(x)+wi(x) ) / γ } from 0 to l
BACDelta [][3]*big.Int // {( βui(x)+αvi(x)+wi(x) ) / δ } from l+1 to m
Z []*big.Int
G1 struct {
Alpha [3]*big.Int
Beta [3]*big.Int
Delta [3]*big.Int
At [][3]*big.Int // {a(τ)} from 0 to m
BACGamma [][3]*big.Int // {( βui(x)+αvi(x)+wi(x) ) / δ } from l+1 to m
BACGamma [][3]*big.Int // {( βui(x)+αvi(x)+wi(x) ) / γ } from 0 to m
}
G2 struct {
Beta [3][2]*big.Int
Gamma [3][2]*big.Int
Delta [3][2]*big.Int
BACGamma [][3][2]*big.Int // {( βui(x)+αvi(x)+wi(x) ) / δ } from l+1 to m
BACGamma [][3][2]*big.Int // {( βui(x)+αvi(x)+wi(x) ) / γ } from 0 to m
}
PowersTauDelta [][3]*big.Int // powers of τ encrypted in G1 curve, divided by δ
}
@@ -165,9 +165,9 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al
bt := Utils.PF.Eval(betas[i], setup.Toxic.T)
g1bt := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, bt)
g2bt := Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, bt)
// G1.BACGamma: {( βui(x)+αvi(x)+wi(x) ) / δ } from l+1 to m in G1
// G1.BACGamma: {( βui(x)+αvi(x)+wi(x) ) / γ } from 0 to m in G1
setup.Pk.G1.BACGamma = append(setup.Pk.G1.BACGamma, g1bt)
// G2.BACGamma: {( βui(x)+αvi(x)+wi(x) ) / δ } from l+1 to m in G2
// G2.BACGamma: {( βui(x)+αvi(x)+wi(x) ) / γ } from 0 to m in G2
setup.Pk.G2.BACGamma = append(setup.Pk.G2.BACGamma, g2bt)
}
@@ -192,7 +192,7 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al
)
g1c := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, c)
// Pk.BACDelta: {( βui(x)+αvi(x)+wi(x) ) / γ } from 0 to l
// Pk.BACDelta: {( βui(x)+αvi(x)+wi(x) ) / δ } from l+1 to m
setup.Pk.BACDelta = append(setup.Pk.BACDelta, g1c)
}

View File

@@ -24,6 +24,7 @@ syn keyword goSnarkCircuitPrivatePublic private public
syn keyword goSnarkCircuitOut out
syn keyword goSnarkCircuitEquals equals
syn keyword goSnarkCircuitFunction func
syn keyword goSnarkCircuitStatement return
syn keyword goSnarkCircuitImport import
syn match goSnarkCircuitFuncCall /\<\K\k*\ze\s*(/
syn keyword goSnarkCircuitPrivate private nextgroup=goSnarkCircuitInputName skipwhite
@@ -46,6 +47,7 @@ hi def link goSnarkCircuitOpSymbols Operator
hi def link goSnarkCircuitFuncCall Function
hi def link goSnarkCircuitEquals Identifier
hi def link goSnarkCircuitFunction Keyword
hi def link goSnarkCircuitStatement Statement
hi def link goSnarkCircuitImport Keyword
hi def link goSnarkCircuitBraces Function
hi def link goSnarkCircuitPrivate Keyword

3
wasm/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
node_modules
package-lock.json
wasm_exec.js

28
wasm/README.md Normal file
View File

@@ -0,0 +1,28 @@
# go-snark wasm
*Warning: this is an ongoing experimentation*
## Wasm usage
To compile to wasm, inside the `wasm` directory, execute:
```
GOARCH=wasm GOOS=js go build -o go-snark.wasm go-snark-wasm-wrapper.go
```
Add the file `wasm_exec.js` in the directory:
```
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
```
Call the library from javascript:
```js
let r = generateProofs(
JSON.stringify(circuit),
JSON.stringify(setup),
JSON.stringify(px),
JSON.stringify(inputs),
);
```
Run the http server that allows to load the `.wasm` file:
```
node server.js
```

View File

@@ -0,0 +1,91 @@
package main
import (
"encoding/json"
"syscall/js"
"github.com/arnaucube/go-snark"
"github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/wasm/utils"
)
func main() {
c := make(chan struct{}, 0)
println("WASM Go Initialized")
// register functions
registerCallbacks()
<-c
}
func registerCallbacks() {
js.Global().Set("generateProofs", js.FuncOf(generateProofs))
}
func generateProofs(this js.Value, i []js.Value) interface{} {
var circuitStr utils.CircuitString
err := json.Unmarshal([]byte(i[0].String()), &circuitStr)
if err != nil {
println(i[0].String())
println("error parsing circuit from stringified json")
}
circuit, err := utils.CircuitFromString(circuitStr)
if err != nil {
println("error " + err.Error())
}
sj, err := json.Marshal(circuit)
if err != nil {
println("error " + err.Error())
}
println("circuit", string(sj))
var setupStr utils.SetupString
println(i[1].String())
err = json.Unmarshal([]byte(i[1].String()), &setupStr)
if err != nil {
println("error parsing setup from stringified json")
}
setup, err := utils.SetupFromString(setupStr)
if err != nil {
println("error " + err.Error())
}
sj, err = json.Marshal(setup)
if err != nil {
println("error " + err.Error())
}
println("set", string(sj))
var pxStr []string
err = json.Unmarshal([]byte(i[2].String()), &pxStr)
if err != nil {
println("error parsing pxStr from stringified json")
}
px, err := utils.ArrayStringToBigInt(pxStr)
if err != nil {
println(err.Error())
}
sj, err = json.Marshal(px)
if err != nil {
println("error " + err.Error())
}
println("px", string(sj))
var inputs circuitcompiler.Inputs
err = json.Unmarshal([]byte(i[3].String()), &inputs)
if err != nil {
println("error parsing inputs from stringified json")
}
w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
proof, err := snark.GenerateProofs(circuit, setup, w, px)
if err != nil {
println("error generating proof", err)
}
proofString := utils.ProofToString(proof)
proofJson, err := json.Marshal(proofString)
if err != nil {
println("error marshal proof to json", err)
}
println("proofJson", string(proofJson))
return js.ValueOf(string(proofJson))
}

BIN
wasm/go-snark.wasm Executable file

Binary file not shown.

19
wasm/index.html Normal file
View File

@@ -0,0 +1,19 @@
<html>
<head>
<meta charset="utf-8">
<title>go-snark wasm experiments</title>
</head>
<body>
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch('go-snark.wasm'), go.importObject).then(function(dat) {
go.run(dat.instance);
});
</script>
<button onClick="callGenerateProof();">Generate Proof</button>
<textarea id="proofResult" rows="15" style="width: 80%;">
</textarea>
<script src="index.js"></script>
</body>
</html>

19
wasm/index.js Normal file

File diff suppressed because one or more lines are too long

15
wasm/package.json Normal file
View File

@@ -0,0 +1,15 @@
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.16.4"
}
}

7
wasm/server.js Normal file
View File

@@ -0,0 +1,7 @@
var express = require('express');
var app = express();
express.static.mime.types['wasm'] = 'application/wasm';
app.use(express.static(__dirname + '/'));
port=8080
app.listen(8080);
console.log("server running at :8080")