github.com/consensys/gnark@v0.11.0/backend/witness/witness_test.go (about) 1 package witness_test 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "reflect" 8 "testing" 9 10 "github.com/consensys/gnark-crypto/ecc" 11 "github.com/consensys/gnark-crypto/ecc/bn254/fr" 12 "github.com/consensys/gnark/backend/witness" 13 "github.com/consensys/gnark/frontend" 14 "github.com/consensys/gnark/io" 15 "github.com/stretchr/testify/require" 16 ) 17 18 type circuit struct { 19 // tagging a variable is optional 20 // default uses variable name and secret visibility. 21 X frontend.Variable `gnark:",public"` 22 Y frontend.Variable `gnark:",public"` 23 24 E frontend.Variable 25 } 26 27 func (c *circuit) Define(frontend.API) error { 28 return nil 29 } 30 31 func ExampleWitness() { 32 // Witnesses can be created directly by "walking" through an assignment (circuit structure) 33 // simple assignment 34 assignment := &circuit{ 35 X: 42, 36 Y: 8000, 37 E: 1, 38 } 39 40 w, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) 41 42 // Binary [de]serialization 43 data, _ := w.MarshalBinary() 44 45 reconstructed, _ := witness.New(ecc.BN254.ScalarField()) 46 reconstructed.UnmarshalBinary(data) 47 48 // For pretty printing, we can do JSON conversions; they are not efficient and don't handle 49 // complex circuit structures well. 50 51 // first get the circuit expected schema 52 schema, _ := frontend.NewSchema(assignment) 53 ret, _ := reconstructed.ToJSON(schema) 54 55 var b bytes.Buffer 56 json.Indent(&b, ret, "", "\t") 57 fmt.Println(b.String()) 58 // Output: 59 // { 60 // "X": 42, 61 // "Y": 8000, 62 // "E": 1 63 // } 64 65 } 66 67 func TestMarshalPublic(t *testing.T) { 68 assert := require.New(t) 69 70 var assignment circuit 71 assignment.X = new(fr.Element).SetInt64(42) 72 assignment.Y = new(fr.Element).SetInt64(8000) 73 74 roundTripMarshal(assert, assignment, true) 75 roundTripMarshalJSON(assert, assignment, true) 76 } 77 78 func TestMarshal(t *testing.T) { 79 assert := require.New(t) 80 81 var assignment circuit 82 assignment.X = new(fr.Element).SetInt64(42) 83 assignment.Y = new(fr.Element).SetInt64(8000) 84 assignment.E = new(fr.Element).SetInt64(1) 85 86 roundTripMarshal(assert, assignment, false) 87 roundTripMarshalJSON(assert, assignment, false) 88 } 89 90 func TestPublic(t *testing.T) { 91 assert := require.New(t) 92 93 var assignment circuit 94 assignment.X = new(fr.Element).SetInt64(42) 95 assignment.Y = new(fr.Element).SetInt64(8000) 96 assignment.E = new(fr.Element).SetInt64(1) 97 98 w, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) 99 assert.NoError(err) 100 101 publicW, err := w.Public() 102 assert.NoError(err) 103 104 wt := publicW.Vector().(fr.Vector) 105 106 assert.Equal(3, len(w.Vector().(fr.Vector))) 107 assert.Equal(2, len(wt)) 108 109 assert.Equal("42", wt[0].String()) 110 assert.Equal("8000", wt[1].String()) 111 } 112 113 func roundTripMarshal(assert *require.Assertions, assignment circuit, publicOnly bool) { 114 var opts []frontend.WitnessOption 115 if publicOnly { 116 opts = append(opts, frontend.PublicOnly()) 117 } 118 w, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField(), opts...) 119 assert.NoError(err) 120 121 assert.NoError(io.RoundTripCheck(w, func() interface{} { 122 rw, err := witness.New(ecc.BN254.ScalarField()) 123 assert.NoError(err) 124 return rw 125 })) 126 } 127 128 func roundTripMarshalJSON(assert *require.Assertions, assignment circuit, publicOnly bool) { 129 // build the vector 130 var opts []frontend.WitnessOption 131 if publicOnly { 132 opts = append(opts, frontend.PublicOnly()) 133 } 134 w, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField(), opts...) 135 assert.NoError(err) 136 137 s, err := frontend.NewSchema(&assignment) 138 assert.NoError(err) 139 140 // serialize the vector to JSON 141 data, err := w.ToJSON(s) 142 assert.NoError(err) 143 144 // re-read 145 rw, err := witness.New(ecc.BN254.ScalarField()) 146 assert.NoError(err) 147 err = rw.FromJSON(s, data) 148 assert.NoError(err) 149 150 assert.True(reflect.DeepEqual(rw, w), "witness json round trip serialization") 151 152 } 153 154 type initableVariable struct { 155 Val []frontend.Variable 156 } 157 158 func (iv *initableVariable) GnarkInitHook() { 159 if iv.Val == nil { 160 iv.Val = []frontend.Variable{1, 2} // need to init value as are assigning to witness 161 } 162 } 163 164 type initableCircuit struct { 165 X [2]initableVariable 166 Y []initableVariable 167 Z initableVariable 168 } 169 170 func (c *initableCircuit) Define(api frontend.API) error { 171 panic("not called") 172 } 173 174 func TestVariableInitHook(t *testing.T) { 175 assert := require.New(t) 176 177 assignment := &initableCircuit{Y: make([]initableVariable, 2)} 178 w, err := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) 179 assert.NoError(err) 180 fw, ok := w.Vector().(fr.Vector) 181 assert.True(ok) 182 assert.Len(fw, 10, "invalid length") 183 }