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

     1  // Copyright 2020 ConsenSys Software Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package witness provides serialization helpers to encode a witness into a []byte.
    16  //
    17  // Binary protocol
    18  //
    19  //	Witness     ->  [uint32(nbPublic) | uint32(nbSecret) | fr.Vector(variables)]
    20  //	fr.Vector is a *field element* vector encoded a big-endian byte array like so: [uint32(len(vector)) | elements]
    21  //
    22  // # Ordering
    23  //
    24  // First, `publicVariables`, then `secretVariables`. Each subset is ordered from the order of definition in the circuit structure.
    25  // For example, with this circuit on `ecc.BN254`
    26  //
    27  //	type Circuit struct {
    28  //	    X frontend.Variable
    29  //	    Y frontend.Variable `gnark:",public"`
    30  //	    Z frontend.Variable
    31  //	}
    32  //
    33  // A valid witness would be:
    34  //   - `[uint32(1)|uint32(2)|uint32(3)|bytes(Y)|bytes(X)|bytes(Z)]`
    35  //   - Hex representation with values `Y = 35`, `X = 3`, `Z = 2`
    36  //     `000000010000000200000003000000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000002`
    37  package witness
    38  
    39  import (
    40  	"bytes"
    41  	"encoding"
    42  	"encoding/binary"
    43  	"encoding/json"
    44  	"errors"
    45  	"fmt"
    46  	"io"
    47  	"math/big"
    48  	"reflect"
    49  
    50  	fr_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr"
    51  	fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
    52  	fr_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/fr"
    53  	fr_bls24317 "github.com/consensys/gnark-crypto/ecc/bls24-317/fr"
    54  	fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr"
    55  	fr_bw6633 "github.com/consensys/gnark-crypto/ecc/bw6-633/fr"
    56  	fr_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/fr"
    57  	"github.com/consensys/gnark/debug"
    58  	"github.com/consensys/gnark/frontend/schema"
    59  	"github.com/consensys/gnark/internal/tinyfield"
    60  )
    61  
    62  var ErrInvalidWitness = errors.New("invalid witness")
    63  
    64  // Witness represents a zkSNARK witness.
    65  //
    66  // The underlying data structure is a vector of field elements, but a Witness
    67  // also may have some additional meta information about the number of public elements and
    68  // secret elements.
    69  //
    70  // In most cases a Witness should be [de]serialized using a binary protocol.
    71  // JSON conversions for pretty printing are slow and don't handle all complex circuit structures well.
    72  type Witness interface {
    73  	io.WriterTo
    74  	io.ReaderFrom
    75  	encoding.BinaryMarshaler
    76  	encoding.BinaryUnmarshaler
    77  
    78  	// Public returns the Public an object containing the public part of the Witness only.
    79  	Public() (Witness, error)
    80  
    81  	// Vector returns the underlying fr.Vector slice
    82  	Vector() any
    83  
    84  	// ToJSON returns the JSON encoding of the witness following the provided Schema. This is a
    85  	// convenience method and should be avoided in most cases.
    86  	ToJSON(s *schema.Schema) ([]byte, error)
    87  
    88  	// FromJSON parses a JSON data input and attempt to reconstruct a witness following the provided Schema.
    89  	// This is a convenience method and should be avoided in most cases.
    90  	FromJSON(s *schema.Schema, data []byte) error
    91  
    92  	// Fill range over the provided chan to fill the underlying vector.
    93  	// Will allocate the underlying vector with nbPublic + nbSecret elements.
    94  	// This is typically call by internal APIs to fill the vector by walking a structure.
    95  	Fill(nbPublic, nbSecret int, values <-chan any) error
    96  }
    97  
    98  type witness struct {
    99  	vector             any
   100  	nbPublic, nbSecret uint32
   101  }
   102  
   103  // New initialize a new empty Witness.
   104  func New(field *big.Int) (Witness, error) {
   105  	v, err := newVector(field, 0)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  
   110  	return &witness{
   111  		vector: v,
   112  	}, nil
   113  }
   114  
   115  func (w *witness) Fill(nbPublic, nbSecret int, values <-chan any) error {
   116  	n := nbPublic + nbSecret
   117  	w.vector = resize(w.vector, n)
   118  	w.nbPublic = uint32(nbPublic)
   119  	w.nbSecret = uint32(nbSecret)
   120  
   121  	i := 0
   122  
   123  	// note; this shouldn't be perf critical but if it is we could have 2 input chan and
   124  	// fill public and secret values concurrently.
   125  	for v := range values {
   126  		if i >= n {
   127  			// we panic here; shouldn't happen and if it does we may leek a chan + producer go routine
   128  			panic("chan of values returns more elements than expected")
   129  		}
   130  		// if v == nil {
   131  		// 	this is caught in the set method. however, error message will be unclear; reason
   132  		// is there is a nil field in assignment, we could print which one.
   133  		// }
   134  		if err := set(w.vector, i, v); err != nil {
   135  			return err
   136  		}
   137  		i++
   138  	}
   139  
   140  	if i != n {
   141  		return fmt.Errorf("expected %d values, filled only %d", n, i)
   142  	}
   143  
   144  	return nil
   145  }
   146  
   147  func (w *witness) iterate() chan any {
   148  	return iterate(w.vector)
   149  }
   150  
   151  func (w *witness) Public() (Witness, error) {
   152  	v, err := newFrom(w.vector, int(w.nbPublic))
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  	return &witness{
   157  		vector:   v,
   158  		nbPublic: w.nbPublic,
   159  	}, nil
   160  }
   161  
   162  func (w *witness) WriteTo(wr io.Writer) (n int64, err error) {
   163  	// write number of public, number of secret
   164  	if err := binary.Write(wr, binary.BigEndian, w.nbPublic); err != nil {
   165  		return 0, err
   166  	}
   167  	n = int64(4)
   168  	if err := binary.Write(wr, binary.BigEndian, w.nbSecret); err != nil {
   169  		return n, err
   170  	}
   171  	n += 4
   172  
   173  	// write the vector
   174  	var m int64
   175  	switch t := w.vector.(type) {
   176  	case fr_bn254.Vector:
   177  		m, err = t.WriteTo(wr)
   178  	case fr_bls12377.Vector:
   179  		m, err = t.WriteTo(wr)
   180  	case fr_bls12381.Vector:
   181  		m, err = t.WriteTo(wr)
   182  	case fr_bw6761.Vector:
   183  		m, err = t.WriteTo(wr)
   184  	case fr_bls24317.Vector:
   185  		m, err = t.WriteTo(wr)
   186  	case fr_bls24315.Vector:
   187  		m, err = t.WriteTo(wr)
   188  	case fr_bw6633.Vector:
   189  		m, err = t.WriteTo(wr)
   190  	case tinyfield.Vector:
   191  		m, err = t.WriteTo(wr)
   192  	default:
   193  		panic("invalid input")
   194  	}
   195  	n += m
   196  	return n, err
   197  }
   198  
   199  func (w *witness) ReadFrom(r io.Reader) (n int64, err error) {
   200  	var buf [4]byte
   201  	if read, err := io.ReadFull(r, buf[:]); err != nil {
   202  		return int64(read), err
   203  	}
   204  	w.nbPublic = binary.BigEndian.Uint32(buf[:4])
   205  	if read, err := io.ReadFull(r, buf[:]); err != nil {
   206  		return int64(read) + 4, err
   207  	}
   208  	w.nbSecret = binary.BigEndian.Uint32(buf[:4])
   209  
   210  	n = 8
   211  
   212  	var m int64
   213  	switch t := w.vector.(type) {
   214  	case fr_bn254.Vector:
   215  		m, err = t.ReadFrom(r)
   216  		w.vector = t
   217  	case fr_bls12377.Vector:
   218  		m, err = t.ReadFrom(r)
   219  		w.vector = t
   220  	case fr_bls12381.Vector:
   221  		m, err = t.ReadFrom(r)
   222  		w.vector = t
   223  	case fr_bw6761.Vector:
   224  		m, err = t.ReadFrom(r)
   225  		w.vector = t
   226  	case fr_bls24317.Vector:
   227  		m, err = t.ReadFrom(r)
   228  		w.vector = t
   229  	case fr_bls24315.Vector:
   230  		m, err = t.ReadFrom(r)
   231  		w.vector = t
   232  	case fr_bw6633.Vector:
   233  		m, err = t.ReadFrom(r)
   234  		w.vector = t
   235  	case tinyfield.Vector:
   236  		m, err = t.ReadFrom(r)
   237  		w.vector = t
   238  	default:
   239  		panic("invalid input")
   240  	}
   241  
   242  	n += m
   243  	return n, err
   244  }
   245  
   246  // MarshalBinary encodes the number of public, number of secret and the fr.Vector.
   247  func (w *witness) MarshalBinary() (data []byte, err error) {
   248  	var buf bytes.Buffer
   249  
   250  	if _, err = w.WriteTo(&buf); err != nil {
   251  		return
   252  	}
   253  	return buf.Bytes(), nil
   254  }
   255  
   256  // UnmarshalBinary implements encoding.BinaryUnmarshaler
   257  func (w *witness) UnmarshalBinary(data []byte) error {
   258  	r := bytes.NewReader(data)
   259  	_, err := w.ReadFrom(r)
   260  	return err
   261  }
   262  
   263  func (w *witness) Vector() any {
   264  	return w.vector
   265  }
   266  
   267  // ToJSON returns the JSON encoding of the witness following the provided Schema. This is a
   268  // convenience method and should be avoided in most cases.
   269  func (w *witness) ToJSON(s *schema.Schema) ([]byte, error) {
   270  	if s.NbPublic != int(w.nbPublic) || (w.nbSecret != 0 && w.nbSecret != uint32(s.NbSecret)) {
   271  		return nil, errors.New("schema is inconsistent with Witness")
   272  	}
   273  	typ := reflect.PointerTo(leafType(w.vector))
   274  	instance := s.Instantiate(typ)
   275  
   276  	chValues := w.iterate()
   277  	if _, err := schema.Walk(instance, typ, func(field schema.LeafInfo, tValue reflect.Value) error {
   278  		if field.Visibility == schema.Public {
   279  			v := <-chValues
   280  			tValue.Set(reflect.ValueOf(v))
   281  		}
   282  		return nil
   283  	}); err != nil {
   284  		return nil, err
   285  	}
   286  
   287  	if w.nbSecret != 0 {
   288  		// secret part.
   289  		if _, err := schema.Walk(instance, typ, func(field schema.LeafInfo, tValue reflect.Value) error {
   290  			if field.Visibility == schema.Secret {
   291  				v := <-chValues
   292  				tValue.Set(reflect.ValueOf(v))
   293  			}
   294  			return nil
   295  		}); err != nil {
   296  			return nil, err
   297  		}
   298  	}
   299  
   300  	if debug.Debug {
   301  		return json.MarshalIndent(instance, "  ", "    ")
   302  	} else {
   303  		return json.Marshal(instance)
   304  	}
   305  }
   306  
   307  // FromJSON parses a JSON data input and attempt to reconstruct a witness following the provided Schema.
   308  // This is a convenience method and should be avoided in most cases.
   309  func (w *witness) FromJSON(s *schema.Schema, data []byte) error {
   310  	typ := leafType(w.vector)
   311  	ptrTyp := reflect.PointerTo(typ)
   312  
   313  	// we instantiate an object matching the schema, with leaf type == field element
   314  	// note that we pass a pointer here to have nil for zero values
   315  	instance := s.Instantiate(ptrTyp)
   316  
   317  	dec := json.NewDecoder(bytes.NewReader(data))
   318  	dec.DisallowUnknownFields()
   319  
   320  	// field.Element (gnark-crypto) implements json.Unmarshaler
   321  	if err := dec.Decode(instance); err != nil {
   322  		return err
   323  	}
   324  	// walk through the public AND secret values
   325  	missingAssignment := func(name string) error {
   326  		return fmt.Errorf("missing assignment for %s", name)
   327  	}
   328  
   329  	// collect all public values; if any are missing, no point going further.
   330  	publicValues := make([]any, 0, s.NbPublic)
   331  	if _, err := schema.Walk(instance, ptrTyp, func(leaf schema.LeafInfo, tValue reflect.Value) error {
   332  		if leaf.Visibility == schema.Public {
   333  			if tValue.IsNil() {
   334  				return missingAssignment(leaf.FullName())
   335  			}
   336  			publicValues = append(publicValues, reflect.Indirect(tValue).Interface())
   337  		}
   338  		return nil
   339  	}); err != nil {
   340  		// missing public values
   341  		return err
   342  	}
   343  
   344  	// collect all secret values; if any are missing, we just deal with the public part.
   345  	secretValues := make([]any, 0, s.NbSecret)
   346  	publicOnly := false
   347  	if _, err := schema.Walk(instance, ptrTyp, func(leaf schema.LeafInfo, tValue reflect.Value) error {
   348  		if leaf.Visibility == schema.Secret {
   349  			if tValue.IsNil() {
   350  				return missingAssignment(leaf.FullName())
   351  			}
   352  			secretValues = append(secretValues, reflect.Indirect(tValue).Interface())
   353  		}
   354  		return nil
   355  	}); err != nil {
   356  		// missing secret values, we just do the public part.
   357  		publicOnly = true
   358  	}
   359  
   360  	// reconstruct the witness
   361  	// we use a buffered channel to ensure this go routine terminates, even if setting a witness
   362  	// value failed. All this is not really performant for large witnesses, but again, JSON
   363  	// shouldn't be used in perf-critical scenario.
   364  	var chValues chan any
   365  	if publicOnly {
   366  		chValues = make(chan any, len(publicValues))
   367  		s.NbSecret = 0
   368  	} else {
   369  		chValues = make(chan any, len(publicValues)+len(secretValues))
   370  	}
   371  	go func() {
   372  		defer close(chValues)
   373  
   374  		for _, v := range publicValues {
   375  			chValues <- v
   376  		}
   377  
   378  		if publicOnly {
   379  			return
   380  		}
   381  
   382  		for _, v := range secretValues {
   383  			chValues <- v
   384  		}
   385  	}()
   386  
   387  	return w.Fill(s.NbPublic, s.NbSecret, chValues)
   388  }