Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add prover gnark example #751

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ exclude = ["ensure-no_std"]
resolver = "2"

[workspace.package]
version = "0.4.0"
version = "0.5.0"
MauroToscano marked this conversation as resolved.
Show resolved Hide resolved
edition = "2021"
license = "Apache-2.0"
repository = "https://github.com/lambdaclass/lambdaworks"
Expand Down
1 change: 1 addition & 0 deletions examples/prove-gnark-plonk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Example of how to use Gnark frontend with lambdaworks
242 changes: 242 additions & 0 deletions examples/prove-gnark-plonk/example.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
// Copyright 2020 ConsenSys AG
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"fmt"
"io/ioutil"
"log"
"reflect"
"unsafe"

"encoding/json"

"github.com/consensys/gnark-crypto/ecc"
fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
"github.com/consensys/gnark/backend/plonk"
plonk_bls12381 "github.com/consensys/gnark/backend/plonk/bls12-381"
"github.com/consensys/gnark/backend/witness"
cs "github.com/consensys/gnark/constraint/bls12-381"
"github.com/consensys/gnark/frontend/cs/scs"
"github.com/consensys/gnark/test"

"github.com/consensys/gnark/frontend"
)

type SerializedCircuit struct {
N int
N_Padded uint64
Omega string
Input []string
Ql []string
Qr []string
Qm []string
Qo []string
Qc []string
A []string
B []string
C []string
Permutation []int64
}

func ToJSON(_r1cs *cs.SparseR1CS, pk *plonk_bls12381.ProvingKey, fullWitness witness.Witness, witnessPublic fr_bls12381.Vector) { // n
nbConstraints := _r1cs.GetNbConstraints()
nbPublic := len(_r1cs.Public)
n := nbConstraints + nbPublic
omega := pk.Domain[0].Generator.Text(16)

// Ql, Qm, Qr, Qo, Qk, S1, S2, S3
var Ql, Qr, Qm, Qo, Qc []string

for i := 0; i < nbPublic; i++ {
var minus_one fr_bls12381.Element
minus_one = fr_bls12381.NewElement(1)
minus_one.Neg(&minus_one)
zero := fr_bls12381.NewElement(0)
Ql = append(Ql, minus_one.Text(16))
Qr = append(Qr, zero.Text(16))
Qm = append(Qm, zero.Text(16))
Qo = append(Qo, zero.Text(16))
Qc = append(Qc, zero.Text(16))
}

constraint_list := _r1cs.GetSparseR1Cs()

for i := 0; i < nbConstraints; i++ { // constraints
Ql = append(Ql, _r1cs.Coefficients[int(constraint_list[i].QL)].Text(16))
Qr = append(Qr, _r1cs.Coefficients[int(constraint_list[i].QR)].Text(16))

var new_Qm fr_bls12381.Element

/*
var new_Qm fr_bls12381.Element
new_Qm.Set(&_r1cs.Coefficients[_r1cs.Constraints[i].M[0].CoeffID()]).Mul(&new_Qm, &_r1cs.Coefficients[_r1cs.Constraints[i].M[1].CoeffID()])

*/
new_Qm.Set(&_r1cs.Coefficients[int(constraint_list[i].QM)])
new_Qm.Double(&new_Qm)
Qm = append(Qm, new_Qm.Text(16))

Qo = append(Qo, _r1cs.Coefficients[int(constraint_list[i].QO)].Text(16))
Qc = append(Qc, _r1cs.Coefficients[int(constraint_list[i].QC)].Text(16))
}

// Witness
// opt, _ := backend.NewProverConfig()
var _solution, _ = _r1cs.Solve(fullWitness)
abc := _solution.(*cs.SparseR1CSSolution)

var a, b, c []string
for i := 0; i < len(_r1cs.Public); i++ {
a = append(a, witnessPublic[i].Text(16))
b = append(b, witnessPublic[0].Text(16))
c = append(c, witnessPublic[0].Text(16))
}
for i := 0; i < nbConstraints; i++ { // constraints
a = append(a, abc.L[i].Text(16))
b = append(b, abc.R[i].Text(16))
c = append(c, abc.O[i].Text(16))
}

var input []string
for i := 0; i < len(_r1cs.Public); i++ {
input = append(input, witnessPublic[i].Text(16))
}

// TODO: Compute the permutation in lambdaworks as to aoid using reflection to get the private field

/*
Permutation is a private field, and for a reason, they are changing the API a lot here. It's a bit different in the current main.

This code needs to be update. Currently working with Gnark 9.1
*/

rs := reflect.ValueOf(pk).Elem()
rf := rs.Field(0)
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()

var trace_pointer plonk_bls12381.Trace = rf.Interface().(plonk_bls12381.Trace)

s := trace_pointer.S
log.Println(s)

data := SerializedCircuit{
N: n,
Omega: omega,
N_Padded: pk.Domain[0].Cardinality,
Input: input,
Ql: Ql,
Qr: Qr,
Qm: Qm,
Qo: Qo,
Qc: Qc,
A: a,
B: b,
C: c,
Permutation: s,
}
file, _ := json.MarshalIndent(data, "", " ")
_ = ioutil.WriteFile("frontend_precomputed_values.json", file, 0644)
}

// In this example we show how to use PLONK with KZG commitments. The circuit that is
// showed here is the same as in ../exponentiate.

// Circuit y == x**e
// only the bitSize least significant bits of e are used
type Circuit struct {
// tagging a variable is optional
// default uses variable name and secret visibility.
X frontend.Variable `gnark:",public"`
Y frontend.Variable `gnark:",public"`
}

// Define declares the circuit's constraints
// y == x**e
func (circuit *Circuit) Define(api frontend.API) error {
api.AssertIsEqual(circuit.Y, api.Add(circuit.X, circuit.X))
return nil
}

func main() {

var circuit Circuit

// // building the circuit...
ccs, err := frontend.Compile(ecc.BLS12_381.ScalarField(), scs.NewBuilder, &circuit)

// var buf bytes.Buffer
// ccs.WriteTo(&buf)

// fmt.Println(json.Marshal(ccs))

if err != nil {
fmt.Println("circuit compilation error")
}

// create the necessary data for KZG.
// This is a toy example, normally the trusted setup to build ZKG
// has been ran before.
// The size of the data in KZG should be the closest power of 2 bounding //
// above max(nbConstraints, nbVariables).
_r1cs := ccs.(*cs.SparseR1CS)
srs, err := test.NewKZGSRS(_r1cs)
if err != nil {
panic(err)
}

// Correct data: the proof passes
{
// Witnesses instantiation. Witness is known only by the prover,
// while public w is a public data known by the verifier.
var w Circuit
w.X = 1
w.Y = 2

witnessFull, err := frontend.NewWitness(&w, ecc.BLS12_381.ScalarField())

if err != nil {
log.Fatal(err)
}

witnessPublic, err := frontend.NewWitness(&w, ecc.BLS12_381.ScalarField(), frontend.PublicOnly())
if err != nil {
log.Fatal(err)
}

// public data consists the polynomials describing the constants involved
// in the constraints, the polynomial describing the permutation ("grand
// product argument"), and the FFT domains.
pk, _, err := plonk.Setup(ccs, srs)

// cs implements io.WriterTo
// var buf bytes.Buffer
// ccs.WriteTo(&buf)

// a, err := json.Marshal(pk)
// fmt.Println(buf)
// fmt.Println(string(buf.Bytes()))

//_, err := plonk.Setup(r1cs, kate, &publicWitness)
if err != nil {
log.Fatal(err)
}

publicWitness, _ := witnessPublic.Vector().(fr_bls12381.Vector)

ToJSON(_r1cs, pk.(*plonk_bls12381.ProvingKey), witnessFull, publicWitness)
}

}
63 changes: 63 additions & 0 deletions examples/prove-gnark-plonk/frontend_precomputed_values.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"N": 3,
"N_Padded": 4,
"Omega": "8d51ccce760304d0ec030002760300000001000000000000",
"Input": [
"1",
"2"
],
"Ql": [
"73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000",
"73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000",
"1"
],
"Qr": [
"0",
"0",
"73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffffeffffffff"
],
"Qm": [
"0",
"0",
"0"
],
"Qo": [
"0",
"0",
"0"
],
"Qc": [
"0",
"0",
"0"
],
"A": [
"1",
"2",
"1"
],
"B": [
"1",
"1",
"1"
],
"C": [
"1",
"1",
"1"
],
"Permutation": [
11,
2,
1,
0,
3,
4,
5,
6,
7,
8,
9,
10
]
}
30 changes: 30 additions & 0 deletions examples/prove-gnark-plonk/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module gnark_example

go 1.20

require (
github.com/consensys/gnark v0.9.1
github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb
)

require (
github.com/bits-and-blooms/bitset v1.8.0 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/consensys/bavard v0.1.13 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fxamacker/cbor/v2 v2.5.0 // indirect
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/rs/zerolog v1.30.0 // indirect
github.com/stretchr/testify v1.8.4 // indirect
github.com/x448/float16 v0.8.4 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.11.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
)
Loading
Loading