@@ -153,15 +153,18 @@ impl MergeExpressionsOptimizer {
153
153
154
154
// Returns the input witnesses used by the opcode
155
155
fn witness_inputs < F : AcirField > ( & self , opcode : & Opcode < F > ) -> BTreeSet < Witness > {
156
- let mut witnesses = BTreeSet :: new ( ) ;
157
156
match opcode {
158
157
Opcode :: AssertZero ( expr) => CircuitSimulator :: expr_wit ( expr) ,
159
- Opcode :: BlackBoxFuncCall ( bb_func) => bb_func. get_input_witnesses ( ) ,
158
+ Opcode :: BlackBoxFuncCall ( bb_func) => {
159
+ let mut witnesses = bb_func. get_input_witnesses ( ) ;
160
+ witnesses. extend ( bb_func. get_outputs_vec ( ) ) ;
161
+
162
+ witnesses
163
+ }
160
164
Opcode :: Directive ( Directive :: ToLeRadix { a, .. } ) => CircuitSimulator :: expr_wit ( a) ,
161
165
Opcode :: MemoryOp { block_id : _, op, predicate } => {
162
166
//index et value, et predicate
163
- let mut witnesses = BTreeSet :: new ( ) ;
164
- witnesses. extend ( CircuitSimulator :: expr_wit ( & op. index ) ) ;
167
+ let mut witnesses = CircuitSimulator :: expr_wit ( & op. index ) ;
165
168
witnesses. extend ( CircuitSimulator :: expr_wit ( & op. value ) ) ;
166
169
if let Some ( p) = predicate {
167
170
witnesses. extend ( CircuitSimulator :: expr_wit ( p) ) ;
@@ -173,6 +176,7 @@ impl MergeExpressionsOptimizer {
173
176
init. iter ( ) . cloned ( ) . collect ( )
174
177
}
175
178
Opcode :: BrilligCall { inputs, outputs, .. } => {
179
+ let mut witnesses = BTreeSet :: new ( ) ;
176
180
for i in inputs {
177
181
witnesses. extend ( self . brillig_input_wit ( i) ) ;
178
182
}
@@ -182,12 +186,9 @@ impl MergeExpressionsOptimizer {
182
186
witnesses
183
187
}
184
188
Opcode :: Call { id : _, inputs, outputs, predicate } => {
185
- for i in inputs {
186
- witnesses. insert ( * i) ;
187
- }
188
- for i in outputs {
189
- witnesses. insert ( * i) ;
190
- }
189
+ let mut witnesses: BTreeSet < Witness > = BTreeSet :: from_iter ( inputs. iter ( ) . copied ( ) ) ;
190
+ witnesses. extend ( outputs) ;
191
+
191
192
if let Some ( p) = predicate {
192
193
witnesses. extend ( CircuitSimulator :: expr_wit ( p) ) ;
193
194
}
@@ -235,15 +236,15 @@ mod tests {
235
236
acir_field:: AcirField ,
236
237
circuit:: {
237
238
brillig:: { BrilligFunctionId , BrilligOutputs } ,
238
- opcodes:: FunctionInput ,
239
+ opcodes:: { BlackBoxFuncCall , FunctionInput } ,
239
240
Circuit , ExpressionWidth , Opcode , PublicInputs ,
240
241
} ,
241
242
native_types:: { Expression , Witness } ,
242
243
FieldElement ,
243
244
} ;
244
245
use std:: collections:: BTreeSet ;
245
246
246
- fn check_circuit ( circuit : Circuit < FieldElement > ) {
247
+ fn check_circuit ( circuit : Circuit < FieldElement > ) -> Circuit < FieldElement > {
247
248
assert ! ( CircuitSimulator :: default ( ) . check_circuit( & circuit) ) ;
248
249
let mut merge_optimizer = MergeExpressionsOptimizer :: new ( ) ;
249
250
let acir_opcode_positions = vec ! [ 0 ; 20 ] ;
@@ -253,6 +254,7 @@ mod tests {
253
254
optimized_circuit. opcodes = opcodes;
254
255
// check that the circuit is still valid after optimization
255
256
assert ! ( CircuitSimulator :: default ( ) . check_circuit( & optimized_circuit) ) ;
257
+ optimized_circuit
256
258
}
257
259
258
260
#[ test]
@@ -352,4 +354,50 @@ mod tests {
352
354
} ;
353
355
check_circuit ( circuit) ;
354
356
}
357
+
358
+ #[ test]
359
+ fn takes_blackbox_opcode_outputs_into_account ( ) {
360
+ // Regression test for https://github.com/noir-lang/noir/issues/6527
361
+ // Previously we would not track the usage of witness 4 in the output of the blackbox function.
362
+ // We would then merge the final two opcodes losing the check that the brillig call must match
363
+ // with `_0 ^ _1`.
364
+
365
+ let circuit: Circuit < FieldElement > = Circuit {
366
+ current_witness_index : 7 ,
367
+ opcodes : vec ! [
368
+ Opcode :: BrilligCall {
369
+ id: BrilligFunctionId ( 0 ) ,
370
+ inputs: Vec :: new( ) ,
371
+ outputs: vec![ BrilligOutputs :: Simple ( Witness ( 3 ) ) ] ,
372
+ predicate: None ,
373
+ } ,
374
+ Opcode :: BlackBoxFuncCall ( BlackBoxFuncCall :: AND {
375
+ lhs: FunctionInput :: witness( Witness ( 0 ) , 8 ) ,
376
+ rhs: FunctionInput :: witness( Witness ( 1 ) , 8 ) ,
377
+ output: Witness ( 4 ) ,
378
+ } ) ,
379
+ Opcode :: AssertZero ( Expression {
380
+ linear_combinations: vec![
381
+ ( FieldElement :: one( ) , Witness ( 3 ) ) ,
382
+ ( -FieldElement :: one( ) , Witness ( 4 ) ) ,
383
+ ] ,
384
+ ..Default :: default ( )
385
+ } ) ,
386
+ Opcode :: AssertZero ( Expression {
387
+ linear_combinations: vec![
388
+ ( -FieldElement :: one( ) , Witness ( 2 ) ) ,
389
+ ( FieldElement :: one( ) , Witness ( 4 ) ) ,
390
+ ] ,
391
+ ..Default :: default ( )
392
+ } ) ,
393
+ ] ,
394
+ expression_width : ExpressionWidth :: Bounded { width : 4 } ,
395
+ private_parameters : BTreeSet :: from ( [ Witness ( 0 ) , Witness ( 1 ) ] ) ,
396
+ return_values : PublicInputs ( BTreeSet :: from ( [ Witness ( 2 ) ] ) ) ,
397
+ ..Default :: default ( )
398
+ } ;
399
+
400
+ let new_circuit = check_circuit ( circuit. clone ( ) ) ;
401
+ assert_eq ! ( circuit, new_circuit) ;
402
+ }
355
403
}
0 commit comments