diff --git a/src/gadgets/sorting.rs b/src/gadgets/sorting.rs index 77d4d173..1547295b 100644 --- a/src/gadgets/sorting.rs +++ b/src/gadgets/sorting.rs @@ -39,8 +39,8 @@ impl, const D: usize> CircuitBuilder { ) -> Vec { let n = ops.len(); - let address_chunk_size = (address_bits as f64).sqrt() as usize; - let timestamp_chunk_size = (timestamp_bits as f64).sqrt() as usize; + let combined_bits = address_bits + timestamp_bits; + let chunk_size = 3; let is_write_targets: Vec<_> = self .add_virtual_targets(n) @@ -65,35 +65,26 @@ impl, const D: usize> CircuitBuilder { }) .collect(); + let two_n = self.constant(F::from_canonical_usize(1 << timestamp_bits)); + let address_timestamp_combined: Vec<_> = output_targets + .iter() + .map(|op| self.mul_add(op.timestamp, two_n, op.address)) + .collect(); + for i in 1..n { - let (address_gate, address_gate_index) = { - let gate = ComparisonGate::new(address_bits, address_chunk_size); + let (gate, gate_index) = { + let gate = ComparisonGate::new(combined_bits, chunk_size); let gate_index = self.add_gate(gate.clone(), vec![]); (gate, gate_index) }; self.connect( - Target::wire(address_gate_index, address_gate.wire_first_input()), - output_targets[i - 1].address, + Target::wire(gate_index, gate.wire_first_input()), + address_timestamp_combined[i - 1], ); self.connect( - Target::wire(address_gate_index, address_gate.wire_second_input()), - output_targets[i].address, - ); - - let (timestamp_gate, timestamp_gate_index) = { - let gate = ComparisonGate::new(timestamp_bits, timestamp_chunk_size); - let gate_index = self.add_gate(gate.clone(), vec![]); - (gate, gate_index) - }; - - self.connect( - Target::wire(timestamp_gate_index, timestamp_gate.wire_first_input()), - output_targets[i - 1].timestamp, - ); - self.connect( - Target::wire(timestamp_gate_index, timestamp_gate.wire_second_input()), - output_targets[i].timestamp, + Target::wire(gate_index, gate.wire_second_input()), + address_timestamp_combined[i], ); } diff --git a/src/gates/comparison.rs b/src/gates/comparison.rs index d928bd6f..86601fba 100644 --- a/src/gates/comparison.rs +++ b/src/gates/comparison.rs @@ -13,7 +13,7 @@ use crate::plonk::plonk_common::{reduce_with_powers, reduce_with_powers_ext_recu use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; use crate::util::ceil_div_usize; -/// A gate for checking that one value is less than another. +/// A gate for checking that one value is less than or equal to another. #[derive(Clone, Debug)] pub(crate) struct ComparisonGate, const D: usize> { pub(crate) num_bits: usize, @@ -137,7 +137,7 @@ impl, const D: usize> Gate for ComparisonGate constraints.push(most_significant_diff - most_significant_diff_so_far); // Range check `most_significant_diff` to be less than `chunk_size`. - let product = (1..chunk_size) + let product = (0..chunk_size) .map(|x| most_significant_diff - F::Extension::from_canonical_usize(x)) .product(); constraints.push(product); @@ -205,7 +205,7 @@ impl, const D: usize> Gate for ComparisonGate constraints.push(most_significant_diff - most_significant_diff_so_far); // Range check `most_significant_diff` to be less than `chunk_size`. - let product = (1..chunk_size) + let product = (0..chunk_size) .map(|x| most_significant_diff - F::from_canonical_usize(x)) .product(); constraints.push(product); @@ -286,7 +286,7 @@ impl, const D: usize> Gate for ComparisonGate // Range check `most_significant_diff` to be less than `chunk_size`. let mut product = builder.one_extension(); - for x in 1..chunk_size { + for x in 0..chunk_size { let x_F = builder.constant_extension(F::Extension::from_canonical_usize(x)); let diff = builder.sub_extension(most_significant_diff, x_F); product = builder.mul_extension(product, diff); @@ -553,7 +553,7 @@ mod tests { let first_input_u64 = rng.gen_range(0..max); let second_input_u64 = { let mut val = rng.gen_range(0..max); - while val <= first_input_u64 { + while val < first_input_u64 { val = rng.gen_range(0..max); } val @@ -562,20 +562,39 @@ mod tests { let first_input = F::from_canonical_u64(first_input_u64); let second_input = F::from_canonical_u64(second_input_u64); - let gate = ComparisonGate:: { + let less_than_gate = ComparisonGate:: { num_bits, num_chunks, _phantom: PhantomData, }; - - let vars = EvaluationVars { + let less_than_vars = EvaluationVars { local_constants: &[], local_wires: &get_wires(first_input, second_input), public_inputs_hash: &HashOut::rand(), }; - assert!( - gate.eval_unfiltered(vars).iter().all(|x| x.is_zero()), + less_than_gate + .eval_unfiltered(less_than_vars) + .iter() + .all(|x| x.is_zero()), + "Gate constraints are not satisfied." + ); + + let equal_gate = ComparisonGate:: { + num_bits, + num_chunks, + _phantom: PhantomData, + }; + let equal_vars = EvaluationVars { + local_constants: &[], + local_wires: &get_wires(first_input, first_input), + public_inputs_hash: &HashOut::rand(), + }; + assert!( + equal_gate + .eval_unfiltered(equal_vars) + .iter() + .all(|x| x.is_zero()), "Gate constraints are not satisfied." ); }