@@ -639,7 +639,7 @@ impl<F: Field> ConstraintSystem<F> {
639639 self . lc_assignment_cache . borrow_mut ( ) . insert ( idx, value) ;
640640 Some ( value)
641641 }
642- }
642+ } ,
643643 }
644644 }
645645}
@@ -1053,4 +1053,119 @@ mod tests {
10531053 assert_eq ! ( matrices. c[ 2 ] , vec![ ( two, 1 ) , ( two, 2 ) ] ) ;
10541054 Ok ( ( ) )
10551055 }
1056+
1057+ #[ test]
1058+ fn matrix_generation_outlined ( ) -> crate :: r1cs:: Result < ( ) > {
1059+ let cs = ConstraintSystem :: < Fr > :: new_ref ( ) ;
1060+ cs. set_optimization_goal ( OptimizationGoal :: Weight ) ;
1061+ let two = Fr :: one ( ) + Fr :: one ( ) ;
1062+ let a = cs. new_input_variable ( || Ok ( Fr :: one ( ) ) ) ?;
1063+ let b = cs. new_witness_variable ( || Ok ( Fr :: one ( ) ) ) ?;
1064+ let c = cs. new_witness_variable ( || Ok ( two) ) ?;
1065+ cs. enforce_constraint ( lc ! ( ) + a, lc ! ( ) + ( two, b) , lc ! ( ) + c) ?;
1066+
1067+ let d = cs. new_lc ( lc ! ( ) + a + b) ?;
1068+ cs. enforce_constraint ( lc ! ( ) + a, lc ! ( ) + d, lc ! ( ) + d) ?;
1069+
1070+ let e = cs. new_lc ( lc ! ( ) + d + d) ?;
1071+ cs. enforce_constraint ( lc ! ( ) + Variable :: One , lc ! ( ) + e, lc ! ( ) + e) ?;
1072+
1073+ cs. finalize ( ) ;
1074+ assert ! ( cs. is_satisfied( ) . is_ok( ) ) ;
1075+ let matrices = cs. to_matrices ( ) . unwrap ( ) ;
1076+ assert_eq ! ( matrices. a[ 0 ] , vec![ ( Fr :: one( ) , 1 ) ] ) ;
1077+ assert_eq ! ( matrices. b[ 0 ] , vec![ ( two, 2 ) ] ) ;
1078+ assert_eq ! ( matrices. c[ 0 ] , vec![ ( Fr :: one( ) , 3 ) ] ) ;
1079+
1080+ assert_eq ! ( matrices. a[ 1 ] , vec![ ( Fr :: one( ) , 1 ) ] ) ;
1081+ // Notice here how the variable allocated for d is outlined
1082+ // compared to the example in previous test case.
1083+ // We are optimising for weight: there are less non-zero elements.
1084+ assert_eq ! ( matrices. b[ 1 ] , vec![ ( Fr :: one( ) , 4 ) ] ) ;
1085+ assert_eq ! ( matrices. c[ 1 ] , vec![ ( Fr :: one( ) , 4 ) ] ) ;
1086+
1087+ assert_eq ! ( matrices. a[ 2 ] , vec![ ( Fr :: one( ) , 0 ) ] ) ;
1088+ assert_eq ! ( matrices. b[ 2 ] , vec![ ( two, 4 ) ] ) ;
1089+ assert_eq ! ( matrices. c[ 2 ] , vec![ ( two, 4 ) ] ) ;
1090+ Ok ( ( ) )
1091+ }
1092+
1093+ /// Example meant to follow as closely as possible the excellent R1CS
1094+ /// write-up by [Vitalik Buterin](https://vitalik.ca/general/2016/12/10/qap.html)
1095+ /// and demonstrate how to construct such matrices in arkworks.
1096+ #[ test]
1097+ fn matrix_generation_example ( ) -> crate :: r1cs:: Result < ( ) > {
1098+ let cs = ConstraintSystem :: < Fr > :: new_ref ( ) ;
1099+ // helper definitions
1100+ let three = Fr :: from ( 3u8 ) ;
1101+ let five = Fr :: from ( 5u8 ) ;
1102+ let nine = Fr :: from ( 9u8 ) ;
1103+ // There will be six variables in the system, in the order governed by adding
1104+ // them to the constraint system (Note that the CS is initialised with
1105+ // `Variable::One` in the first position implicitly).
1106+ // Note also that the all public variables will always be placed before all witnesses
1107+ //
1108+ // Variable::One
1109+ // Variable::Instance(5)
1110+ // Variable::Witness(3) ( == x )
1111+ // Variable::Witness(9) ( == sym_1 )
1112+ // Variable::Witness(27) ( == y )
1113+ // Variable::Witness(30) ( == y )
1114+
1115+ // let one = Variable::One; // public input, implicitly defined
1116+ let out = cs. new_input_variable ( || Ok ( nine * three + three + five) ) ?; // public input
1117+ let x = cs. new_witness_variable ( || Ok ( three) ) ?; // explicit witness
1118+ let sym_1 = cs. new_witness_variable ( || Ok ( nine) ) ?; // intermediate witness variable
1119+ let y = cs. new_witness_variable ( || Ok ( nine * three) ) ?; // intermediate witness variable
1120+ let sym_2 = cs. new_witness_variable ( || Ok ( nine * three + three) ) ?; // intermediate witness variable
1121+
1122+ cs. enforce_constraint ( lc ! ( ) + x, lc ! ( ) + x, lc ! ( ) + sym_1) ?;
1123+ cs. enforce_constraint ( lc ! ( ) + sym_1, lc ! ( ) + x, lc ! ( ) + y) ?;
1124+ cs. enforce_constraint ( lc ! ( ) + y + x, lc ! ( ) + Variable :: One , lc ! ( ) + sym_2) ?;
1125+ cs. enforce_constraint (
1126+ lc ! ( ) + sym_2 + ( five, Variable :: One ) ,
1127+ lc ! ( ) + Variable :: One ,
1128+ lc ! ( ) + out,
1129+ ) ?;
1130+
1131+ cs. finalize ( ) ;
1132+ assert ! ( cs. is_satisfied( ) . is_ok( ) ) ;
1133+ let matrices = cs. to_matrices ( ) . unwrap ( ) ;
1134+ // There are four gates(constraints), each generating a row.
1135+ // Resulting matrices:
1136+ // (Note how 2nd & 3rd columns are swapped compared to the online example.
1137+ // This results from an implementation detail of placing all Variable::Instances(_) first.
1138+ //
1139+ // A
1140+ // [0, 0, 1, 0, 0, 0]
1141+ // [0, 0, 0, 1, 0, 0]
1142+ // [0, 0, 1, 0, 1, 0]
1143+ // [5, 0, 0, 0, 0, 1]
1144+ // B
1145+ // [0, 0, 1, 0, 0, 0]
1146+ // [0, 0, 1, 0, 0, 0]
1147+ // [1, 0, 0, 0, 0, 0]
1148+ // [1, 0, 0, 0, 0, 0]
1149+ // C
1150+ // [0, 0, 0, 1, 0, 0]
1151+ // [0, 0, 0, 0, 1, 0]
1152+ // [0, 0, 0, 0, 0, 1]
1153+ // [0, 1, 0, 0, 0, 0]
1154+ assert_eq ! ( matrices. a[ 0 ] , vec![ ( Fr :: one( ) , 2 ) ] ) ;
1155+ assert_eq ! ( matrices. b[ 0 ] , vec![ ( Fr :: one( ) , 2 ) ] ) ;
1156+ assert_eq ! ( matrices. c[ 0 ] , vec![ ( Fr :: one( ) , 3 ) ] ) ;
1157+
1158+ assert_eq ! ( matrices. a[ 1 ] , vec![ ( Fr :: one( ) , 3 ) ] ) ;
1159+ assert_eq ! ( matrices. b[ 1 ] , vec![ ( Fr :: one( ) , 2 ) ] ) ;
1160+ assert_eq ! ( matrices. c[ 1 ] , vec![ ( Fr :: one( ) , 4 ) ] ) ;
1161+
1162+ assert_eq ! ( matrices. a[ 2 ] , vec![ ( Fr :: one( ) , 2 ) , ( Fr :: one( ) , 4 ) ] ) ;
1163+ assert_eq ! ( matrices. b[ 2 ] , vec![ ( Fr :: one( ) , 0 ) ] ) ;
1164+ assert_eq ! ( matrices. c[ 2 ] , vec![ ( Fr :: one( ) , 5 ) ] ) ;
1165+
1166+ assert_eq ! ( matrices. a[ 3 ] , vec![ ( five, 0 ) , ( Fr :: one( ) , 5 ) ] ) ;
1167+ assert_eq ! ( matrices. b[ 3 ] , vec![ ( Fr :: one( ) , 0 ) ] ) ;
1168+ assert_eq ! ( matrices. c[ 3 ] , vec![ ( Fr :: one( ) , 1 ) ] ) ;
1169+ Ok ( ( ) )
1170+ }
10561171}
0 commit comments