From 6cce4c1f782c9189937c154a27335338376ffbbd Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 10 Jun 2021 15:55:29 +0200 Subject: [PATCH] Add low-high split --- src/gadgets/mod.rs | 1 + src/gadgets/range_check.rs | 62 ++++++++++++++++++++++++++++++++++++++ src/gates/base_sum.rs | 9 ++---- 3 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 src/gadgets/range_check.rs diff --git a/src/gadgets/mod.rs b/src/gadgets/mod.rs index ee331012..636f8afc 100644 --- a/src/gadgets/mod.rs +++ b/src/gadgets/mod.rs @@ -2,5 +2,6 @@ pub mod arithmetic; pub mod hash; pub mod interpolation; pub mod polynomial; +pub mod range_check; pub mod split_base; pub(crate) mod split_join; diff --git a/src/gadgets/range_check.rs b/src/gadgets/range_check.rs new file mode 100644 index 00000000..4323923d --- /dev/null +++ b/src/gadgets/range_check.rs @@ -0,0 +1,62 @@ +use crate::circuit_builder::CircuitBuilder; +use crate::field::extension_field::Extendable; +use crate::field::field::Field; +use crate::gates::base_sum::BaseSumGate; +use crate::generator::SimpleGenerator; +use crate::target::Target; +use crate::witness::PartialWitness; + +impl, const D: usize> CircuitBuilder { + /// Checks that `x < 2^n_log` using a `BaseSumGate`. + pub fn range_check(&mut self, x: Target, n_log: usize) { + let gate = self.add_gate(BaseSumGate::<2>::new(n_log), vec![]); + let sum = Target::wire(gate, BaseSumGate::<2>::WIRE_SUM); + self.route(x, sum); + } + + /// Returns `(a,b)` such that `x = a + 2^n_log * b` with `a < 2^n_log`. + pub fn split_low_high(&mut self, x: Target, n_log: usize) -> (Target, Target) { + let low_gate = self.add_gate(BaseSumGate::<2>::new(n_log), vec![]); + let high_gate = self.add_gate(BaseSumGate::<2>::new(n_log), vec![]); + let low = Target::wire(low_gate, BaseSumGate::<2>::WIRE_SUM); + let high = Target::wire(high_gate, BaseSumGate::<2>::WIRE_SUM); + self.add_generator(LowHighGenerator { + integer: x, + n_log, + low, + high, + }); + + let pow2 = self.constant(F::from_canonical_u64(1 << n_log)); + let comp_x = self.mul_add(high, pow2, low); + self.assert_equal(x, comp_x); + + (low, high) + } +} + +#[derive(Debug)] +struct LowHighGenerator { + integer: Target, + n_log: usize, + low: Target, + high: Target, +} + +impl SimpleGenerator for LowHighGenerator { + fn dependencies(&self) -> Vec { + vec![self.integer] + } + + fn run_once(&self, witness: &PartialWitness) -> PartialWitness { + let mut integer_value = witness.get_target(self.integer).to_canonical_u64(); + let low = integer_value & ((1 << self.n_log) - 1); + let high = integer_value >> self.n_log; + + let mut result = PartialWitness::new(); + result.set_target(self.low, F::from_canonical_u64(low)); + result.set_target(self.high, F::from_canonical_u64(high)); + + result + } +} diff --git a/src/gates/base_sum.rs b/src/gates/base_sum.rs index ef69b802..3efb6533 100644 --- a/src/gates/base_sum.rs +++ b/src/gates/base_sum.rs @@ -71,7 +71,7 @@ impl, const D: usize, const B: usize> Gate for BaseSumGat let reversed_computed_sum = reduce_with_powers_recursive(builder, &limbs, base); let mut constraints = vec![ builder.sub_extension(computed_sum, sum), - builder.sub_extension(reversed_computed_sum, computed_sum), + builder.sub_extension(reversed_computed_sum, reversed_sum), ]; for limb in limbs { constraints.push({ @@ -127,10 +127,7 @@ pub struct BaseSplitGenerator { impl SimpleGenerator for BaseSplitGenerator { fn dependencies(&self) -> Vec { - vec![Target::Wire(Wire { - gate: self.gate_index, - input: BaseSumGate::::WIRE_SUM, - })] + vec![Target::wire(self.gate_index, BaseSumGate::::WIRE_SUM)] } fn run_once(&self, witness: &PartialWitness) -> PartialWitness { @@ -161,7 +158,7 @@ impl SimpleGenerator for BaseSplitGenerator { debug_assert_eq!( sum_value, 0, - "Integer too large to fit in given number of bits" + "Integer too large to fit in given number of limbs" ); result