Skip to content

Commit

Permalink
Merge pull request #142 from ConsenSys/frontend-println-tests
Browse files Browse the repository at this point in the history
feat: consistant support of `cs.Println` and `debugInfo`
  • Loading branch information
gbotrel authored Sep 20, 2021
2 parents 18202a3 + f624d36 commit 35e8704
Show file tree
Hide file tree
Showing 81 changed files with 1,805 additions and 1,746 deletions.
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

0 comments on commit 35e8704

Please sign in to comment.