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

feat: consistant support of cs.Println and debugInfo #142

Merged
merged 15 commits into from
Sep 20, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
52 changes: 52 additions & 0 deletions backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
// Package backend implements Zero Knowledge Proof systems: it consumes circuit compiled with gnark/frontend.
package backend

import (
"io"
"os"

"github.com/consensys/gnark/backend/hint"
)

// ID represent a unique ID for a proving scheme
type ID uint16

Expand All @@ -40,3 +47,48 @@ func (id ID) String() string {
return "unknown"
}
}

// NewProverOption returns a default ProverOption with given options applied
func NewProverOption(opts ...func(opt *ProverOption) error) (ProverOption, error) {
opt := ProverOption{LoggerOut: os.Stdout}
for _, option := range opts {
if err := option(&opt); err != nil {
return ProverOption{}, err
}
}
return opt, nil
}

// ProverOption is shared accross backends to parametrize calls to xxx.Prove(...)
type ProverOption struct {
Force bool // default to false
HintFunctions []hint.Function // default to nil (use only solver std hints)
LoggerOut io.Writer // default to os.Stdout
}

// IgnoreSolverError is a ProverOption that indicates that the Prove algorithm
// should complete, even if constraint system is not solved.
// In that case, Prove will output an invalid Proof, but will execute all algorithms
// which is useful for test and benchmarking purposes
func IgnoreSolverError(opt *ProverOption) error {
opt.Force = true
return nil
}

// WithHints is a Prover option that specifies additional hint functions to be used
// by the constraint solver
func WithHints(hintFunctions ...hint.Function) func(opt *ProverOption) error {
return func(opt *ProverOption) error {
opt.HintFunctions = append(opt.HintFunctions, hintFunctions...)
return nil
}
}

// WithOutput is a Prover option that specifies an io.Writer as destination for logs printed by
// cs.Println(). If set to nil, no logs are printed.
func WithOutput(w io.Writer) func(opt *ProverOption) error {
return func(opt *ProverOption) error {
opt.LoggerOut = w
return nil
}
}
41 changes: 24 additions & 17 deletions backend/groth16/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"reflect"
"testing"

"github.com/consensys/gnark/backend/hint"
"github.com/consensys/gnark/backend"
"github.com/consensys/gnark/frontend"
backend_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/cs"
witness_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/witness"
Expand All @@ -47,11 +47,11 @@ func NewAssert(t *testing.T) *Assert {
}

// ProverFailed check that a witness does NOT solve a circuit
func (assert *Assert) ProverFailed(r1cs frontend.CompiledConstraintSystem, witness frontend.Circuit, hintFunctions ...hint.Function) {
func (assert *Assert) ProverFailed(r1cs frontend.CompiledConstraintSystem, witness frontend.Circuit, opts ...func(opt *backend.ProverOption) error) {
// setup
pk, err := DummySetup(r1cs)
assert.NoError(err)
_, err = Prove(r1cs, pk, witness, hintFunctions)
_, err = Prove(r1cs, pk, witness, opts...)
assert.Error(err, "proving with bad witness should output an error")
}

Expand All @@ -68,7 +68,7 @@ func (assert *Assert) ProverFailed(r1cs frontend.CompiledConstraintSystem, witne
// 5. Ensure deserialization(serialization) of generated objects is correct
//
// ensure result vectors a*b=c, and check other properties like random sampling
func (assert *Assert) ProverSucceeded(r1cs frontend.CompiledConstraintSystem, witness frontend.Circuit, hintFunctions ...hint.Function) {
func (assert *Assert) ProverSucceeded(r1cs frontend.CompiledConstraintSystem, witness frontend.Circuit, opts ...func(opt *backend.ProverOption) error) {
// setup
pk, vk, err := Setup(r1cs)
assert.NoError(err)
Expand All @@ -84,17 +84,17 @@ func (assert *Assert) ProverSucceeded(r1cs frontend.CompiledConstraintSystem, wi
}

// ensure expected Values are computed correctly
assert.SolvingSucceeded(r1cs, witness, hintFunctions...)
assert.SolvingSucceeded(r1cs, witness, opts...)

// extract full witness & public witness

// prover
proof, err := Prove(r1cs, pk, witness, hintFunctions)
proof, err := Prove(r1cs, pk, witness, opts...)
assert.NoError(err, "proving with good witness should not output an error")

// ensure random sampling; calling prove twice with same witness should produce different proof
{
proof2, err := Prove(r1cs, pk, witness, hintFunctions)
proof2, err := Prove(r1cs, pk, witness, opts...)
assert.NoError(err, "proving with good witness should not output an error")
assert.False(reflect.DeepEqual(proof, proof2), "calling prove twice with same input should produce different proof")
}
Expand Down Expand Up @@ -130,49 +130,56 @@ func (assert *Assert) SerializationRawSucceeded(from gnarkio.WriterRawTo, to io.
}

// SolvingSucceeded Verifies that the R1CS is solved with the given witness, without executing groth16 workflow
func (assert *Assert) SolvingSucceeded(r1cs frontend.CompiledConstraintSystem, witness frontend.Circuit, hintFunctions ...hint.Function) {
assert.NoError(IsSolved(r1cs, witness, hintFunctions))
func (assert *Assert) SolvingSucceeded(r1cs frontend.CompiledConstraintSystem, witness frontend.Circuit, opts ...func(opt *backend.ProverOption) error) {
assert.NoError(IsSolved(r1cs, witness, opts...))
}

// SolvingFailed Verifies that the R1CS is not solved with the given witness, without executing groth16 workflow
func (assert *Assert) SolvingFailed(r1cs frontend.CompiledConstraintSystem, witness frontend.Circuit, hintFunctions ...hint.Function) {
assert.Error(IsSolved(r1cs, witness, hintFunctions))
func (assert *Assert) SolvingFailed(r1cs frontend.CompiledConstraintSystem, witness frontend.Circuit, opts ...func(opt *backend.ProverOption) error) {
assert.Error(IsSolved(r1cs, witness, opts...))
}

// IsSolved attempts to solve the constraint system with provided witness
// returns nil if it succeeds, error otherwise.
func IsSolved(r1cs frontend.CompiledConstraintSystem, witness frontend.Circuit, hintFunctions []hint.Function) error {
func IsSolved(r1cs frontend.CompiledConstraintSystem, witness frontend.Circuit, opts ...func(opt *backend.ProverOption) error) error {

// apply options
opt, err := backend.NewProverOption(opts...)
if err != nil {
return err
}

switch _r1cs := r1cs.(type) {
case *backend_bls12377.R1CS:
w := witness_bls12377.Witness{}
if err := w.FromFullAssignment(witness); err != nil {
return err
}
return _r1cs.IsSolved(w, hintFunctions)
return _r1cs.IsSolved(w, opt)
case *backend_bls12381.R1CS:
w := witness_bls12381.Witness{}
if err := w.FromFullAssignment(witness); err != nil {
return err
}
return _r1cs.IsSolved(w, hintFunctions)
return _r1cs.IsSolved(w, opt)
case *backend_bn254.R1CS:
w := witness_bn254.Witness{}
if err := w.FromFullAssignment(witness); err != nil {
return err
}
return _r1cs.IsSolved(w, hintFunctions)
return _r1cs.IsSolved(w, opt)
case *backend_bw6761.R1CS:
w := witness_bw6761.Witness{}
if err := w.FromFullAssignment(witness); err != nil {
return err
}
return _r1cs.IsSolved(w, hintFunctions)
return _r1cs.IsSolved(w, opt)
case *backend_bls24315.R1CS:
w := witness_bls24315.Witness{}
if err := w.FromFullAssignment(witness); err != nil {
return err
}
return _r1cs.IsSolved(w, hintFunctions)
return _r1cs.IsSolved(w, opt)
default:
panic("unrecognized R1CS curve type")
}
Expand Down
57 changes: 29 additions & 28 deletions backend/groth16/fuzz.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,42 @@
package groth16

import (
"strings"

"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/frontend"
backend_bls12381 "github.com/consensys/gnark/internal/backend/bls12-381/cs"
witness_bls12381 "github.com/consensys/gnark/internal/backend/bls12-381/witness"
backend_bn254 "github.com/consensys/gnark/internal/backend/bn254/cs"
witness_bn254 "github.com/consensys/gnark/internal/backend/bn254/witness"
// backend_bls12381 "github.com/consensys/gnark/internal/backend/bls12-381/cs"
// witness_bls12381 "github.com/consensys/gnark/internal/backend/bls12-381/witness"
// backend_bn254 "github.com/consensys/gnark/internal/backend/bn254/cs"
// witness_bn254 "github.com/consensys/gnark/internal/backend/bn254/witness"
)

// TODO FIXME @gbotrel
func Fuzz(data []byte) int {
curves := []ecc.ID{ecc.BN254, ecc.BLS12_381}
for _, curveID := range curves {
ccs, nbAssertions := frontend.CsFuzzed(data, curveID)
_, s, p := ccs.GetNbVariables()
wSize := s + p - 1
ccs.SetLoggerOutput(nil)
switch _r1cs := ccs.(type) {
case *backend_bls12381.R1CS:
w := make(witness_bls12381.Witness, wSize)
// make w random
err := _r1cs.IsSolved(w, nil)
if nbAssertions == 0 && err != nil && !strings.Contains(err.Error(), "couldn't solve computational constraint") {
panic("no assertions, yet solving resulted in an error.")
}
case *backend_bn254.R1CS:
w := make(witness_bn254.Witness, wSize)
// make w random
err := _r1cs.IsSolved(w, nil)
if nbAssertions == 0 && err != nil && !strings.Contains(err.Error(), "couldn't solve computational constraint") {
panic("no assertions, yet solving resulted in an error.")
}
default:
panic("unrecognized R1CS curve type")
}
frontend.CsFuzzed(data, curveID)
// _, s, p := ccs.GetNbVariables()
// wSize := s + p - 1
// ccs.SetLoggerOutput(nil)
// switch _r1cs := ccs.(type) {
// case *backend_bls12381.R1CS:
// w := make(witness_bls12381.Witness, wSize)
// // make w random
// _ = _r1cs.IsSolved(w, nil)
// // TODO FIXME @gbotrel
// // if nbAssertions == 0 && err != nil && !strings.Contains(err.Error(), "couldn't solve computational constraint") {
// // panic("no assertions, yet solving resulted in an error.")
// // }
// case *backend_bn254.R1CS:
// w := make(witness_bn254.Witness, wSize)
// // make w random
// _ = _r1cs.IsSolved(w, nil)
// // TODO FIXME @gbotrel
// // if nbAssertions == 0 && err != nil && !strings.Contains(err.Error(), "couldn't solve computational constraint") {
// // panic("no assertions, yet solving resulted in an error.")
// // }
// default:
// panic("unrecognized R1CS curve type")
}
// }
return 1
}
41 changes: 22 additions & 19 deletions backend/groth16/groth16.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (

"github.com/consensys/gnark-crypto/ecc"

"github.com/consensys/gnark/backend/hint"
"github.com/consensys/gnark/backend"
"github.com/consensys/gnark/frontend"
backend_bls12377 "github.com/consensys/gnark/internal/backend/bls12-377/cs"
backend_bls12381 "github.com/consensys/gnark/internal/backend/bls12-381/cs"
Expand Down Expand Up @@ -188,11 +188,12 @@ func ReadAndVerify(proof Proof, vk VerifyingKey, publicWitness io.Reader) error
// will executes all the prover computations, even if the witness is invalid
// will produce an invalid proof
// internally, the solution vector to the R1CS will be filled with random values which may impact benchmarking
func Prove(r1cs frontend.CompiledConstraintSystem, pk ProvingKey, witness frontend.Circuit, hintFunctions []hint.Function, force ...bool) (Proof, error) {
func Prove(r1cs frontend.CompiledConstraintSystem, pk ProvingKey, witness frontend.Circuit, opts ...func(opt *backend.ProverOption) error) (Proof, error) {

_force := false
if len(force) > 0 {
_force = force[0]
// apply options
opt, err := backend.NewProverOption(opts...)
if err != nil {
return nil, err
}

switch _r1cs := r1cs.(type) {
Expand All @@ -201,31 +202,31 @@ func Prove(r1cs frontend.CompiledConstraintSystem, pk ProvingKey, witness fronte
if err := w.FromFullAssignment(witness); err != nil {
return nil, err
}
return groth16_bls12377.Prove(_r1cs, pk.(*groth16_bls12377.ProvingKey), w, hintFunctions, _force)
return groth16_bls12377.Prove(_r1cs, pk.(*groth16_bls12377.ProvingKey), w, opt)
case *backend_bls12381.R1CS:
w := witness_bls12381.Witness{}
if err := w.FromFullAssignment(witness); err != nil {
return nil, err
}
return groth16_bls12381.Prove(_r1cs, pk.(*groth16_bls12381.ProvingKey), w, hintFunctions, _force)
return groth16_bls12381.Prove(_r1cs, pk.(*groth16_bls12381.ProvingKey), w, opt)
case *backend_bn254.R1CS:
w := witness_bn254.Witness{}
if err := w.FromFullAssignment(witness); err != nil {
return nil, err
}
return groth16_bn254.Prove(_r1cs, pk.(*groth16_bn254.ProvingKey), w, hintFunctions, _force)
return groth16_bn254.Prove(_r1cs, pk.(*groth16_bn254.ProvingKey), w, opt)
case *backend_bw6761.R1CS:
w := witness_bw6761.Witness{}
if err := w.FromFullAssignment(witness); err != nil {
return nil, err
}
return groth16_bw6761.Prove(_r1cs, pk.(*groth16_bw6761.ProvingKey), w, hintFunctions, _force)
return groth16_bw6761.Prove(_r1cs, pk.(*groth16_bw6761.ProvingKey), w, opt)
case *backend_bls24315.R1CS:
w := witness_bls24315.Witness{}
if err := w.FromFullAssignment(witness); err != nil {
return nil, err
}
return groth16_bls24315.Prove(_r1cs, pk.(*groth16_bls24315.ProvingKey), w, hintFunctions, _force)
return groth16_bls24315.Prove(_r1cs, pk.(*groth16_bls24315.ProvingKey), w, opt)
default:
panic("unrecognized R1CS curve type")
}
Expand All @@ -234,10 +235,12 @@ func Prove(r1cs frontend.CompiledConstraintSystem, pk ProvingKey, witness fronte
// ReadAndProve behaves like Prove, , except witness is read from a io.Reader
// witness must be encoded following the binary serialization protocol described in
// gnark/backend/witness package
func ReadAndProve(r1cs frontend.CompiledConstraintSystem, pk ProvingKey, witness io.Reader, hintFunctions []hint.Function, force ...bool) (Proof, error) {
_force := false
if len(force) > 0 {
_force = force[0]
func ReadAndProve(r1cs frontend.CompiledConstraintSystem, pk ProvingKey, witness io.Reader, opts ...func(opt *backend.ProverOption) error) (Proof, error) {

// apply options
opt, err := backend.NewProverOption(opts...)
if err != nil {
return nil, err
}

_, nbSecret, nbPublic := r1cs.GetNbVariables()
Expand All @@ -249,31 +252,31 @@ func ReadAndProve(r1cs frontend.CompiledConstraintSystem, pk ProvingKey, witness
if _, err := w.LimitReadFrom(witness, expectedSize); err != nil {
return nil, err
}
return groth16_bls12377.Prove(_r1cs, pk.(*groth16_bls12377.ProvingKey), w, hintFunctions, _force)
return groth16_bls12377.Prove(_r1cs, pk.(*groth16_bls12377.ProvingKey), w, opt)
case *backend_bls12381.R1CS:
w := witness_bls12381.Witness{}
if _, err := w.LimitReadFrom(witness, expectedSize); err != nil {
return nil, err
}
return groth16_bls12381.Prove(_r1cs, pk.(*groth16_bls12381.ProvingKey), w, hintFunctions, _force)
return groth16_bls12381.Prove(_r1cs, pk.(*groth16_bls12381.ProvingKey), w, opt)
case *backend_bn254.R1CS:
w := witness_bn254.Witness{}
if _, err := w.LimitReadFrom(witness, expectedSize); err != nil {
return nil, err
}
return groth16_bn254.Prove(_r1cs, pk.(*groth16_bn254.ProvingKey), w, hintFunctions, _force)
return groth16_bn254.Prove(_r1cs, pk.(*groth16_bn254.ProvingKey), w, opt)
case *backend_bw6761.R1CS:
w := witness_bw6761.Witness{}
if _, err := w.LimitReadFrom(witness, expectedSize); err != nil {
return nil, err
}
return groth16_bw6761.Prove(_r1cs, pk.(*groth16_bw6761.ProvingKey), w, hintFunctions, _force)
return groth16_bw6761.Prove(_r1cs, pk.(*groth16_bw6761.ProvingKey), w, opt)
case *backend_bls24315.R1CS:
w := witness_bls24315.Witness{}
if _, err := w.LimitReadFrom(witness, expectedSize); err != nil {
return nil, err
}
return groth16_bls24315.Prove(_r1cs, pk.(*groth16_bls24315.ProvingKey), w, hintFunctions, _force)
return groth16_bls24315.Prove(_r1cs, pk.(*groth16_bls24315.ProvingKey), w, opt)
default:
panic("unrecognized R1CS curve type")
}
Expand Down
Loading