Browse Source

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

pull/14/head
arnaucube 5 years ago
parent
commit
0a162482ee
14 changed files with 260 additions and 6 deletions
  1. +3
    -0
      .travis.yml
  2. +12
    -0
      README.md
  3. +55
    -0
      cli/main.go
  4. BIN
      go-snark-cli
  5. +6
    -6
      groth16/groth16.go
  6. +2
    -0
      vim-syntax/syntax/go-snark-circuit.vim
  7. +3
    -0
      wasm/.gitignore
  8. +28
    -0
      wasm/README.md
  9. +91
    -0
      wasm/go-snark-wasm-wrapper.go
  10. BIN
      wasm/go-snark.wasm
  11. +19
    -0
      wasm/index.html
  12. +19
    -0
      wasm/index.js
  13. +15
    -0
      wasm/package.json
  14. +7
    -0
      wasm/server.js

+ 3
- 0
.travis.yml

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

+ 12
- 0
README.md

@ -40,7 +40,11 @@ Improvements from the minimal implementation:
- [ ] move witness values calculation outside the setup phase - [ ] move witness values calculation outside the setup phase
- [x] Groth16 - [x] Groth16
- [ ] multiple optimizations - [ ] 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 ## Usage
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark?status.svg)](https://godoc.org/github.com/arnaucube/go-snark) zkSnark - [![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 > ./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. 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`. 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 #### 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: 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:

+ 55
- 0
cli/main.go

@ -15,6 +15,7 @@ import (
"github.com/arnaucube/go-snark/circuitcompiler" "github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/groth16" "github.com/arnaucube/go-snark/groth16"
"github.com/arnaucube/go-snark/r1csqap" "github.com/arnaucube/go-snark/r1csqap"
"github.com/arnaucube/go-snark/wasm/utils"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -96,6 +97,11 @@ func CompileCircuit(context *cli.Context) error {
circuitPath := context.Args().Get(0) circuitPath := context.Args().Get(0)
wasmFlag := false
if context.Args().Get(1) == "wasm" {
wasmFlag = true
}
// read circuit file // read circuit file
circuitFile, err := os.Open(circuitPath) circuitFile, err := os.Open(circuitPath)
panicErr(err) panicErr(err)
@ -185,10 +191,48 @@ func CompileCircuit(context *cli.Context) error {
jsonFile.Close() jsonFile.Close()
fmt.Println("Compiled Circuit data written to ", jsonFile.Name()) 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 return nil
} }
func TrustedSetup(context *cli.Context) error { func TrustedSetup(context *cli.Context) error {
wasmFlag := false
if context.Args().Get(0) == "wasm" {
wasmFlag = true
}
// open compiledcircuit.json // open compiledcircuit.json
compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json") compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
panicErr(err) panicErr(err)
@ -243,6 +287,17 @@ func TrustedSetup(context *cli.Context) error {
jsonFile.Write(jsonData) jsonFile.Write(jsonData)
jsonFile.Close() jsonFile.Close()
fmt.Println("Trusted Setup data written to ", jsonFile.Name()) 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 return nil
} }

BIN
go-snark-cli


+ 6
- 6
groth16/groth16.go

@ -24,20 +24,20 @@ type Setup struct {
// public // public
Pk struct { // Proving Key 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 Z []*big.Int
G1 struct { G1 struct {
Alpha [3]*big.Int Alpha [3]*big.Int
Beta [3]*big.Int Beta [3]*big.Int
Delta [3]*big.Int Delta [3]*big.Int
At [][3]*big.Int // {a(τ)} from 0 to m 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 { G2 struct {
Beta [3][2]*big.Int Beta [3][2]*big.Int
Gamma [3][2]*big.Int Gamma [3][2]*big.Int
Delta [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 δ 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) bt := Utils.PF.Eval(betas[i], setup.Toxic.T)
g1bt := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, bt) g1bt := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, bt)
g2bt := Utils.Bn.G2.MulScalar(Utils.Bn.G2.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) 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) 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) 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) setup.Pk.BACDelta = append(setup.Pk.BACDelta, g1c)
} }

+ 2
- 0
vim-syntax/syntax/go-snark-circuit.vim

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

+ 3
- 0
wasm/.gitignore

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

+ 28
- 0
wasm/README.md

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

+ 91
- 0
wasm/go-snark-wasm-wrapper.go

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


+ 19
- 0
wasm/index.html

@ -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
- 0
wasm/index.js
File diff suppressed because it is too large
View File


+ 15
- 0
wasm/package.json

@ -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
- 0
wasm/server.js

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

Loading…
Cancel
Save