@@ -393,9 +393,33 @@ void build_constraints_parallel(UltraCircuitBuilder& builder,
393393 profile_and_collect (constraints.logic_constraints , [](UltraCircuitBuilder& b, const LogicConstraint& c) {
394394 create_logic_gate (b, c.a , c.b , c.result , c.num_bits , c.is_xor_gate );
395395 });
396- profile_and_collect (constraints.range_constraints , [](UltraCircuitBuilder& b, const RangeConstraint& c) {
397- b.create_dyadic_range_constraint (c.witness , c.num_bits , " parallel range constraint" );
398- });
396+ // Range constraints must be grouped by num_bits since different bit widths produce different gate counts.
397+ {
398+ // Group range constraints by num_bits
399+ std::map<uint32_t , std::vector<size_t >> range_groups; // num_bits -> indices into range_constraints
400+ for (size_t i = 0 ; i < constraints.range_constraints .size (); i++) {
401+ range_groups[constraints.range_constraints [i].num_bits ].push_back (i);
402+ }
403+ auto handler = [](UltraCircuitBuilder& b, const RangeConstraint& c) {
404+ b.create_dyadic_range_constraint (c.witness , c.num_bits , " parallel range constraint" );
405+ };
406+ for (auto & [num_bits, indices] : range_groups) {
407+ auto & representative = constraints.range_constraints [indices[0 ]];
408+ auto profile = profile_constraint_type (representative, handler, num_witnesses);
409+ size_t profile_idx = profiles.size ();
410+ profiles.push_back (profile);
411+ auto sizes = profile.block_sizes ;
412+ sizes.num_rom_arrays = profile.num_rom_arrays_per_instance ;
413+ sizes.num_ram_arrays = profile.num_ram_arrays_per_instance ;
414+ for (size_t idx : indices) {
415+ tasks.emplace_back ([handler, &constraints, idx](UltraCircuitBuilder& b) {
416+ handler (b, constraints.range_constraints [idx]);
417+ });
418+ task_sizes.push_back (sizes);
419+ task_profile_indices.push_back (profile_idx);
420+ }
421+ }
422+ }
399423 profile_and_collect (constraints.aes128_constraints ,
400424 [](UltraCircuitBuilder& b, const AES128Constraint& c) { create_aes128_constraints (b, c); });
401425 profile_and_collect (constraints.sha256_compression , [](UltraCircuitBuilder& b, const Sha256Compression& c) {
0 commit comments