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 }