github.com/consensys/gnark@v0.11.0/test/commitments_test.go (about) 1 package test 2 3 import ( 4 "fmt" 5 "reflect" 6 "testing" 7 8 "github.com/consensys/gnark/backend" 9 groth16 "github.com/consensys/gnark/backend/groth16/bn254" 10 "github.com/consensys/gnark/backend/witness" 11 cs "github.com/consensys/gnark/constraint/bn254" 12 "github.com/consensys/gnark/frontend/cs/r1cs" 13 "github.com/stretchr/testify/require" 14 15 "github.com/consensys/gnark-crypto/ecc" 16 "github.com/consensys/gnark/frontend" 17 "github.com/consensys/gnark/frontend/cs/scs" 18 "github.com/stretchr/testify/assert" 19 ) 20 21 type noCommitmentCircuit struct { 22 X frontend.Variable 23 } 24 25 func (c *noCommitmentCircuit) Define(api frontend.API) error { 26 api.AssertIsEqual(c.X, 1) 27 api.AssertIsEqual(c.X, 1) 28 return nil 29 } 30 31 type commitmentCircuit struct { 32 Public []frontend.Variable `gnark:",public"` 33 X []frontend.Variable 34 } 35 36 func (c *commitmentCircuit) Define(api frontend.API) error { 37 38 commitment, err := api.(frontend.Committer).Commit(c.X...) 39 if err != nil { 40 return err 41 } 42 sum := frontend.Variable(0) 43 for i, x := range c.X { 44 sum = api.Add(sum, api.Mul(x, i+1)) 45 } 46 for _, p := range c.Public { 47 sum = api.Add(sum, p) 48 } 49 api.AssertIsDifferent(commitment, sum) 50 return nil 51 } 52 53 type committedConstantCircuit struct { 54 X frontend.Variable 55 } 56 57 func (c *committedConstantCircuit) Define(api frontend.API) error { 58 commitment, err := api.(frontend.Committer).Commit(1, c.X) 59 if err != nil { 60 return err 61 } 62 api.AssertIsDifferent(commitment, c.X) 63 return nil 64 } 65 66 type committedPublicCircuit struct { 67 X frontend.Variable `gnark:",public"` 68 } 69 70 func (c *committedPublicCircuit) Define(api frontend.API) error { 71 commitment, err := api.(frontend.Committer).Commit(c.X) 72 if err != nil { 73 return err 74 } 75 api.AssertIsDifferent(commitment, c.X) 76 return nil 77 } 78 79 type independentCommitsCircuit struct { 80 X []frontend.Variable 81 } 82 83 func (c *independentCommitsCircuit) Define(api frontend.API) error { 84 committer := api.(frontend.Committer) 85 for i := range c.X { 86 if ch, err := committer.Commit(c.X[i]); err != nil { 87 return err 88 } else { 89 api.AssertIsDifferent(ch, c.X[i]) 90 } 91 } 92 return nil 93 } 94 95 type twoCommitCircuit struct { 96 X []frontend.Variable 97 Y frontend.Variable 98 } 99 100 func (c *twoCommitCircuit) Define(api frontend.API) error { 101 c0, err := api.(frontend.Committer).Commit(c.X...) 102 if err != nil { 103 return err 104 } 105 var c1 frontend.Variable 106 if c1, err = api.(frontend.Committer).Commit(c0, c.Y); err != nil { 107 return err 108 } 109 api.AssertIsDifferent(c1, c.Y) 110 return nil 111 } 112 113 type doubleCommitCircuit struct { 114 X, Y frontend.Variable 115 } 116 117 func (c *doubleCommitCircuit) Define(api frontend.API) error { 118 var c0, c1 frontend.Variable 119 var err error 120 if c0, err = api.(frontend.Committer).Commit(c.X); err != nil { 121 return err 122 } 123 if c1, err = api.(frontend.Committer).Commit(c.X, c.Y); err != nil { 124 return err 125 } 126 api.AssertIsDifferent(c0, c1) 127 return nil 128 } 129 130 func TestHollow(t *testing.T) { 131 132 run := func(c, expected frontend.Circuit) func(t *testing.T) { 133 return func(t *testing.T) { 134 seen := hollow(c) 135 assert.Equal(t, expected, seen) 136 } 137 } 138 139 assignments := []frontend.Circuit{ 140 &committedConstantCircuit{1}, 141 &commitmentCircuit{X: []frontend.Variable{1}, Public: []frontend.Variable{}}, 142 } 143 144 expected := []frontend.Circuit{ 145 &committedConstantCircuit{nil}, 146 &commitmentCircuit{X: []frontend.Variable{nil}, Public: []frontend.Variable{}}, 147 } 148 149 for i := range assignments { 150 t.Run(removePackageName(reflect.TypeOf(assignments[i]).String()), run(assignments[i], expected[i])) 151 } 152 } 153 154 type commitUniquenessCircuit struct { 155 X []frontend.Variable 156 } 157 158 func (c *commitUniquenessCircuit) Define(api frontend.API) error { 159 var err error 160 161 ch := make([]frontend.Variable, len(c.X)) 162 for i := range c.X { 163 if ch[i], err = api.(frontend.Committer).Commit(c.X[i]); err != nil { 164 return err 165 } 166 for j := 0; j < i; j++ { 167 api.AssertIsDifferent(ch[i], ch[j]) 168 } 169 } 170 return nil 171 } 172 173 func TestCommitUniquenessZerosScs(t *testing.T) { // TODO @Tabaie Randomize Groth16 commitments for real 174 175 w, err := frontend.NewWitness(&commitUniquenessCircuit{[]frontend.Variable{0, 0}}, ecc.BN254.ScalarField()) 176 assert.NoError(t, err) 177 178 ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &commitUniquenessCircuit{[]frontend.Variable{nil, nil}}) 179 assert.NoError(t, err) 180 181 _, err = ccs.Solve(w) 182 assert.NoError(t, err) 183 } 184 185 var commitmentTestCircuits []frontend.Circuit 186 187 func init() { 188 commitmentTestCircuits = []frontend.Circuit{ 189 &noCommitmentCircuit{1}, 190 &commitmentCircuit{X: []frontend.Variable{1}, Public: []frontend.Variable{}}, // single commitment 191 &commitmentCircuit{X: []frontend.Variable{1, 2}, Public: []frontend.Variable{}}, // two commitments 192 &commitmentCircuit{X: []frontend.Variable{1, 2, 3, 4, 5}, Public: []frontend.Variable{}}, // five commitments 193 &commitmentCircuit{X: []frontend.Variable{0}, Public: []frontend.Variable{1}}, // single commitment single public 194 &commitmentCircuit{X: []frontend.Variable{0, 1, 2, 3, 4}, Public: []frontend.Variable{1, 2, 3, 4, 5}}, // five commitments five public 195 &committedConstantCircuit{1}, // single committed constant 196 &committedPublicCircuit{1}, // single committed public 197 &independentCommitsCircuit{X: []frontend.Variable{1, 1}}, // two independent commitments 198 &twoCommitCircuit{X: []frontend.Variable{1, 2}, Y: 3}, // two commitments, second depending on first 199 &doubleCommitCircuit{X: 1, Y: 2}, // double committing to the same variable 200 } 201 } 202 203 func TestCommitment(t *testing.T) { 204 t.Parallel() 205 assert := NewAssert(t) 206 207 for i, assignment := range commitmentTestCircuits { 208 assert.Run(func(assert *Assert) { 209 assert.CheckCircuit(hollow(assignment), WithValidAssignment(assignment), WithBackends(backend.GROTH16, backend.PLONK)) 210 }, fmt.Sprintf("%d-%s", i, removePackageName(reflect.TypeOf(assignment).String()))) 211 } 212 } 213 214 func TestCommitmentDummySetup(t *testing.T) { 215 t.Parallel() 216 217 run := func(assignment frontend.Circuit) func(t *testing.T) { 218 return func(t *testing.T) { 219 // just test the prover 220 _cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, hollow(assignment)) 221 require.NoError(t, err) 222 _r1cs := _cs.(*cs.R1CS) 223 var ( 224 dPk, pk groth16.ProvingKey 225 vk groth16.VerifyingKey 226 w witness.Witness 227 ) 228 require.NoError(t, groth16.Setup(_r1cs, &pk, &vk)) 229 require.NoError(t, groth16.DummySetup(_r1cs, &dPk)) 230 231 comparePkSizes(t, dPk, pk) 232 233 w, err = frontend.NewWitness(assignment, ecc.BN254.ScalarField()) 234 require.NoError(t, err) 235 _, err = groth16.Prove(_r1cs, &pk, w) 236 require.NoError(t, err) 237 } 238 } 239 240 for _, assignment := range commitmentTestCircuits { 241 name := removePackageName(reflect.TypeOf(assignment).String()) 242 if c, ok := assignment.(*commitmentCircuit); ok { 243 name += fmt.Sprintf(":%dprivate %dpublic", len(c.X), len(c.Public)) 244 } 245 t.Run(name, run(assignment)) 246 } 247 } 248 249 func comparePkSizes(t *testing.T, pk1, pk2 groth16.ProvingKey) { 250 // skipping the domain 251 require.Equal(t, len(pk1.G1.A), len(pk2.G1.A)) 252 require.Equal(t, len(pk1.G1.B), len(pk2.G1.B)) 253 require.Equal(t, len(pk1.G1.Z), len(pk2.G1.Z)) 254 require.Equal(t, len(pk1.G1.K), len(pk2.G1.K)) 255 256 require.Equal(t, len(pk1.G2.B), len(pk2.G2.B)) 257 258 require.Equal(t, len(pk1.InfinityA), len(pk2.InfinityA)) 259 require.Equal(t, len(pk1.InfinityB), len(pk2.InfinityB)) 260 require.Equal(t, pk1.NbInfinityA, pk2.NbInfinityA) 261 require.Equal(t, pk1.NbInfinityB, pk2.NbInfinityB) 262 263 require.Equal(t, len(pk1.CommitmentKeys), len(pk2.CommitmentKeys)) // TODO @Tabaie Compare the commitment keys 264 }