github.com/consensys/gnark@v0.11.0/frontend/witness.go (about)

     1  package frontend
     2  
     3  import (
     4  	"math/big"
     5  	"reflect"
     6  
     7  	"github.com/consensys/gnark/backend/witness"
     8  	"github.com/consensys/gnark/frontend/schema"
     9  )
    10  
    11  // NewWitness build an ordered vector of field elements from the given assignment (Circuit)
    12  // if PublicOnly is specified, returns the public part of the witness only
    13  // else returns [public | secret]. The result can then be serialized to / from json & binary.
    14  //
    15  // See ExampleWitness in witness package for usage.
    16  func NewWitness(assignment Circuit, field *big.Int, opts ...WitnessOption) (witness.Witness, error) {
    17  	opt, err := options(opts...)
    18  	if err != nil {
    19  		return nil, err
    20  	}
    21  
    22  	// count the leaves
    23  	s, err := schema.Walk(assignment, tVariable, nil)
    24  	if err != nil {
    25  		return nil, err
    26  	}
    27  	if opt.publicOnly {
    28  		s.Secret = 0
    29  	}
    30  
    31  	// allocate the witness
    32  	w, err := witness.New(field)
    33  	if err != nil {
    34  		return nil, err
    35  	}
    36  
    37  	// write the public | secret values in a chan
    38  	chValues := make(chan any)
    39  	go func() {
    40  		defer close(chValues)
    41  		schema.Walk(assignment, tVariable, func(leaf schema.LeafInfo, tValue reflect.Value) error {
    42  			if leaf.Visibility == schema.Public {
    43  				chValues <- tValue.Interface()
    44  			}
    45  			return nil
    46  		})
    47  		if !opt.publicOnly {
    48  			schema.Walk(assignment, tVariable, func(leaf schema.LeafInfo, tValue reflect.Value) error {
    49  				if leaf.Visibility == schema.Secret {
    50  					chValues <- tValue.Interface()
    51  				}
    52  				return nil
    53  			})
    54  		}
    55  	}()
    56  	if err := w.Fill(s.Public, s.Secret, chValues); err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	return w, nil
    61  }
    62  
    63  // NewSchema returns the schema corresponding to the circuit structure.
    64  //
    65  // This is used to JSON (un)marshall witnesses.
    66  func NewSchema(circuit Circuit) (*schema.Schema, error) {
    67  	return schema.New(circuit, tVariable)
    68  }
    69  
    70  // default options
    71  func options(opts ...WitnessOption) (witnessConfig, error) {
    72  	// apply options
    73  	opt := witnessConfig{
    74  		publicOnly: false,
    75  	}
    76  	for _, option := range opts {
    77  		if err := option(&opt); err != nil {
    78  			return opt, err
    79  		}
    80  	}
    81  
    82  	return opt, nil
    83  }
    84  
    85  // WitnessOption sets optional parameter to witness instantiation from an assignment
    86  type WitnessOption func(*witnessConfig) error
    87  
    88  type witnessConfig struct {
    89  	publicOnly bool
    90  }
    91  
    92  // PublicOnly enables to instantiate a witness with the public part only of the assignment
    93  func PublicOnly() WitnessOption {
    94  	return func(opt *witnessConfig) error {
    95  		opt.publicOnly = true
    96  		return nil
    97  	}
    98  }