mirror of
https://github.com/arnaucube/go-snark-study.git
synced 2026-02-02 17:26:41 +01:00
wasm proof generation from browser working. Added cli wasm exporters, html&js browser example, wasm wrapper from go
This commit is contained in:
@@ -5,3 +5,6 @@ go:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
- GO111MODULE=on
|
- GO111MODULE=on
|
||||||
|
|
||||||
|
before_install: rm wasm/go-snark-wasm-wrapper.go
|
||||||
|
|
||||||
|
|||||||
12
README.md
12
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
|
||||||
- [](https://godoc.org/github.com/arnaucube/go-snark) zkSnark
|
- [](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
cli/main.go
55
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
BIN
go-snark-cli
Binary file not shown.
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
wasm/.gitignore
vendored
Normal file
3
wasm/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
node_modules
|
||||||
|
package-lock.json
|
||||||
|
wasm_exec.js
|
||||||
28
wasm/README.md
Normal file
28
wasm/README.md
Normal 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
|
||||||
|
```
|
||||||
91
wasm/go-snark-wasm-wrapper.go
Normal file
91
wasm/go-snark-wasm-wrapper.go
Normal 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
BIN
wasm/go-snark.wasm
Executable file
Binary file not shown.
19
wasm/index.html
Normal file
19
wasm/index.html
Normal 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
19
wasm/index.js
Normal file
File diff suppressed because one or more lines are too long
15
wasm/package.json
Normal file
15
wasm/package.json
Normal 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
7
wasm/server.js
Normal 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")
|
||||||
Reference in New Issue
Block a user