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:
|
||||
- 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
|
||||
- [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
|
||||
- [](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:
|
||||
|
||||
55
cli/main.go
55
cli/main.go
@@ -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
|
||||
}
|
||||
|
||||
|
||||
BIN
go-snark-cli
BIN
go-snark-cli
Binary file not shown.
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
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