@@ -367,10 +367,14 @@ pub fn validate_witness<F: AcirField>(
367367 solver. check_memory_op ( op, & witness_map, opcode_index) ?;
368368 }
369369 Opcode :: MemoryInit { block_id, init, .. } => {
370- MemoryOpSolver :: new ( init, & witness_map) . map ( |solver| {
371- let existing_block_id = block_solvers. insert ( * block_id, solver) ;
372- assert ! ( existing_block_id. is_none( ) , "Memory block already initialized" ) ;
373- } ) ?;
370+ let solver = MemoryOpSolver :: new ( init, & witness_map) ?;
371+ let existing_block_id = block_solvers. insert ( * block_id, solver) ;
372+ if existing_block_id. is_some ( ) {
373+ return Err ( unsatisfied_constraint (
374+ opcode_index,
375+ format ! ( "Attempted reinitialization of memory block {:?}" , block_id. 0 , ) ,
376+ ) ) ;
377+ }
374378 }
375379 // BrilligCall is unconstrained
376380 Opcode :: BrilligCall { .. } => ( ) ,
@@ -443,14 +447,32 @@ mod tests {
443447 use acir:: {
444448 AcirField , FieldElement ,
445449 circuit:: {
446- Circuit , Opcode , PublicInputs ,
447- opcodes:: { BlackBoxFuncCall , FunctionInput } ,
450+ Circuit , Opcode , OpcodeLocation , PublicInputs ,
451+ brillig:: { BrilligFunctionId , BrilligInputs , BrilligOutputs } ,
452+ opcodes:: { AcirFunctionId , BlackBoxFuncCall , BlockId , FunctionInput , MemOp } ,
448453 } ,
449454 native_types:: { Expression , Witness , WitnessMap } ,
450455 } ;
451456 use bn254_blackbox_solver:: Bn254BlackBoxSolver ;
452457
453458 use super :: validate_witness;
459+ use crate :: pwg:: {
460+ ErrorLocation , OpcodeNotSolvable , OpcodeResolutionError , ResolvedAssertionPayload ,
461+ } ;
462+
463+ fn assert_unsatisfied_constraint (
464+ result : Result < ( ) , OpcodeResolutionError < FieldElement > > ,
465+ opcode_index : usize ,
466+ message : & str ,
467+ ) {
468+ assert_eq ! (
469+ result. unwrap_err( ) ,
470+ OpcodeResolutionError :: UnsatisfiedConstrain {
471+ opcode_location: ErrorLocation :: Resolved ( OpcodeLocation :: Acir ( opcode_index) ) ,
472+ payload: Some ( ResolvedAssertionPayload :: String ( message. to_string( ) ) ) ,
473+ } ,
474+ ) ;
475+ }
454476
455477 /// Helper to create a simple circuit with the given opcodes
456478 fn make_circuit ( opcodes : Vec < Opcode < FieldElement > > ) -> Circuit < FieldElement > {
@@ -511,7 +533,11 @@ mod tests {
511533 ] ) ) ;
512534
513535 let backend = Bn254BlackBoxSolver ;
514- assert ! ( validate_witness( & backend, witness_map, & circuit) . is_err( ) ) ;
536+ assert_unsatisfied_constraint (
537+ validate_witness ( & backend, witness_map, & circuit) ,
538+ 0 ,
539+ "Invalid witness assignment: w1 + w2 - w3" ,
540+ ) ;
515541 }
516542
517543 #[ test]
@@ -564,7 +590,11 @@ mod tests {
564590 ] ) ) ;
565591
566592 let backend = Bn254BlackBoxSolver ;
567- assert ! ( validate_witness( & backend, witness_map, & circuit) . is_err( ) ) ;
593+ assert_unsatisfied_constraint (
594+ validate_witness ( & backend, witness_map, & circuit) ,
595+ 0 ,
596+ "RANGE opcode violation: value 256 does not fit in 8 bits" ,
597+ ) ;
568598 }
569599
570600 #[ test]
@@ -604,7 +634,11 @@ mod tests {
604634 ] ) ) ;
605635
606636 let backend = Bn254BlackBoxSolver ;
607- assert ! ( validate_witness( & backend, witness_map, & circuit) . is_err( ) ) ;
637+ assert_unsatisfied_constraint (
638+ validate_witness ( & backend, witness_map, & circuit) ,
639+ 0 ,
640+ "AND opcode violation: 10 AND 12 != 15 for 8 bits" ,
641+ ) ;
608642 }
609643
610644 #[ test]
@@ -644,7 +678,11 @@ mod tests {
644678 ] ) ) ;
645679
646680 let backend = Bn254BlackBoxSolver ;
647- assert ! ( validate_witness( & backend, witness_map, & circuit) . is_err( ) ) ;
681+ assert_unsatisfied_constraint (
682+ validate_witness ( & backend, witness_map, & circuit) ,
683+ 0 ,
684+ "XOR opcode violation: 10 XOR 12 != 15 for 8 bits" ,
685+ ) ;
648686 }
649687
650688 #[ test]
@@ -661,15 +699,15 @@ mod tests {
661699 let witness_map = WitnessMap :: default ( ) ;
662700
663701 let backend = Bn254BlackBoxSolver ;
664- // The expression evaluates with missing witness, but won't be zero
665- // so this should fail
666- assert ! ( validate_witness( & backend, witness_map, & circuit) . is_err( ) ) ;
702+ assert_unsatisfied_constraint (
703+ validate_witness ( & backend, witness_map, & circuit) ,
704+ 0 ,
705+ "Invalid witness assignment: w1" ,
706+ ) ;
667707 }
668708
669709 #[ test]
670710 fn test_call_opcode_valid ( ) {
671- use acir:: circuit:: opcodes:: AcirFunctionId ;
672-
673711 let circuit = make_circuit ( vec ! [ Opcode :: Call {
674712 id: AcirFunctionId ( 1 ) ,
675713 inputs: vec![ Witness ( 1 ) , Witness ( 2 ) ] ,
@@ -689,8 +727,6 @@ mod tests {
689727
690728 #[ test]
691729 fn test_call_opcode_missing_input ( ) {
692- use acir:: circuit:: opcodes:: AcirFunctionId ;
693-
694730 let circuit = make_circuit ( vec ! [ Opcode :: Call {
695731 id: AcirFunctionId ( 1 ) ,
696732 inputs: vec![ Witness ( 1 ) , Witness ( 2 ) ] ,
@@ -705,13 +741,14 @@ mod tests {
705741 ] ) ) ;
706742
707743 let backend = Bn254BlackBoxSolver ;
708- assert ! ( validate_witness( & backend, witness_map, & circuit) . is_err( ) ) ;
744+ assert_eq ! (
745+ validate_witness( & backend, witness_map, & circuit) . unwrap_err( ) ,
746+ OpcodeResolutionError :: OpcodeNotSolvable ( OpcodeNotSolvable :: MissingAssignment ( 2 ) ) ,
747+ ) ;
709748 }
710749
711750 #[ test]
712751 fn test_call_opcode_missing_output ( ) {
713- use acir:: circuit:: opcodes:: AcirFunctionId ;
714-
715752 let circuit = make_circuit ( vec ! [ Opcode :: Call {
716753 id: AcirFunctionId ( 1 ) ,
717754 inputs: vec![ Witness ( 1 ) , Witness ( 2 ) ] ,
@@ -726,13 +763,14 @@ mod tests {
726763 ] ) ) ;
727764
728765 let backend = Bn254BlackBoxSolver ;
729- assert ! ( validate_witness( & backend, witness_map, & circuit) . is_err( ) ) ;
766+ assert_eq ! (
767+ validate_witness( & backend, witness_map, & circuit) . unwrap_err( ) ,
768+ OpcodeResolutionError :: OpcodeNotSolvable ( OpcodeNotSolvable :: MissingAssignment ( 3 ) ) ,
769+ ) ;
730770 }
731771
732772 #[ test]
733773 fn test_call_opcode_skipped_with_zero_predicate ( ) {
734- use acir:: circuit:: opcodes:: AcirFunctionId ;
735-
736774 // Predicate is zero, so call should be skipped even with missing witnesses
737775 let circuit = make_circuit ( vec ! [ Opcode :: Call {
738776 id: AcirFunctionId ( 1 ) ,
@@ -756,8 +794,6 @@ mod tests {
756794
757795 #[ test]
758796 fn test_memory_init_and_read ( ) {
759- use acir:: circuit:: opcodes:: { BlockId , MemOp } ;
760-
761797 let block_id = BlockId ( 0 ) ;
762798
763799 let circuit = make_circuit ( vec ! [
@@ -784,8 +820,6 @@ mod tests {
784820
785821 #[ test]
786822 fn test_memory_read_wrong_value ( ) {
787- use acir:: circuit:: opcodes:: { BlockId , MemOp } ;
788-
789823 let block_id = BlockId ( 0 ) ;
790824
791825 let circuit = make_circuit ( vec ! [
@@ -805,13 +839,15 @@ mod tests {
805839 ] ) ) ;
806840
807841 let backend = Bn254BlackBoxSolver ;
808- assert ! ( validate_witness( & backend, witness_map, & circuit) . is_err( ) ) ;
842+ assert_unsatisfied_constraint (
843+ validate_witness ( & backend, witness_map, & circuit) ,
844+ 1 ,
845+ "Memory read opcode violation at index 0: expected 42 but found 99" ,
846+ ) ;
809847 }
810848
811849 #[ test]
812850 fn test_memory_write_then_read ( ) {
813- use acir:: circuit:: opcodes:: { BlockId , MemOp } ;
814-
815851 let block_id = BlockId ( 0 ) ;
816852
817853 let circuit = make_circuit ( vec ! [
@@ -841,8 +877,6 @@ mod tests {
841877
842878 #[ test]
843879 fn test_brillig_call_with_empty_witness_map ( ) {
844- use acir:: circuit:: brillig:: { BrilligFunctionId , BrilligInputs , BrilligOutputs } ;
845-
846880 // Create a BrilligCall opcode with input and output witnesses
847881 // Brillig calls are unconstrained and should be skipped during validation,
848882 // so this should pass even with an empty witness map
@@ -862,4 +896,31 @@ mod tests {
862896 let backend = Bn254BlackBoxSolver ;
863897 assert ! ( validate_witness( & backend, witness_map, & circuit) . is_ok( ) ) ;
864898 }
899+
900+ #[ test]
901+ fn error_on_memory_init_duplicate_block_id ( ) {
902+ let block_id = BlockId ( 0 ) ;
903+
904+ let circuit = make_circuit ( vec ! [
905+ Opcode :: MemoryInit {
906+ block_id,
907+ init: vec![ ] ,
908+ block_type: acir:: circuit:: opcodes:: BlockType :: Memory ,
909+ } ,
910+ Opcode :: MemoryInit {
911+ block_id,
912+ init: vec![ ] ,
913+ block_type: acir:: circuit:: opcodes:: BlockType :: Memory ,
914+ } ,
915+ ] ) ;
916+
917+ let witness_map = WitnessMap :: default ( ) ;
918+ let backend = Bn254BlackBoxSolver ;
919+
920+ assert_unsatisfied_constraint (
921+ validate_witness ( & backend, witness_map, & circuit) ,
922+ 1 ,
923+ format ! ( "Attempted reinitialization of memory block {}" , block_id. 0 ) . as_str ( ) ,
924+ ) ;
925+ }
865926}
0 commit comments