Browse Source

added fn in RangeCheckChip

Janmajaya Mall 4 years ago
parent
commit
e51ba71306
1 changed files with 83 additions and 1 deletions
  1. 83 1
      src/zk/gadget/range_check.rs

+ 83 - 1
src/zk/gadget/range_check.rs

@@ -3,7 +3,7 @@ use std::marker::PhantomData;
 use group::ff::PrimeFieldBits;
 use group::ff::PrimeFieldBits;
 use halo2_proofs::{
 use halo2_proofs::{
     arithmetic::FieldExt,
     arithmetic::FieldExt,
-    circuit::{Chip, Layouter, Value},
+    circuit::{AssignedCell, Chip, Layouter, Region, Value},
     plonk::{Advice, Column, ConstraintSystem, Error, Selector, TableColumn},
     plonk::{Advice, Column, ConstraintSystem, Error, Selector, TableColumn},
     poly::Rotation,
     poly::Rotation,
 };
 };
@@ -79,4 +79,86 @@ impl<F: FieldExt + PrimeFieldBits, const WINDOW_SIZE: usize> RangeCheckChip<F, W
             },
             },
         )
         )
     }
     }
+
+    pub fn range_check(
+        &self,
+        mut layouter: impl Layouter<F>,
+        element: AssignedCell<F, F>,
+        num_of_bits: usize,
+        num_of_windows: usize,
+    ) -> Result<(), Error> {
+        assert!(WINDOW_SIZE * num_of_windows < num_of_bits + WINDOW_SIZE);
+
+        layouter.assign_region(
+            || "name",
+            |mut region: Region<'_, F>| {
+                // enable selectors
+                for index in 0..num_of_windows {
+                    self.config.s_rc.enable(&mut region, index);
+                }
+
+                // copy element to z_0
+                let z_0 = element.copy_advice(|| "z_0", &mut region, self.config.z, 0)?;
+
+                let mut z_values: Vec<AssignedCell<F, F>> = vec![z_0.clone()];
+                let mut z = z_0.clone();
+                let decomposed_chunks = z_0
+                    .value()
+                    .map(|val| decompose_value::<F, WINDOW_SIZE>(val, num_of_bits))
+                    .transpose_vec(num_of_windows);
+
+                let two_pow_k_inverse =
+                    Value::known(F::from(1 << WINDOW_SIZE as u64).invert().unwrap());
+                for (i, chunk) in decomposed_chunks.iter().enumerate() {
+                    let z_next = {
+                        let z_curr = z.value().copied();
+                        let chunk_value = chunk
+                            .map(|c| F::from(c.iter().fold(0, |acc, c| (acc << 1) + *c as u64)));
+                        // z_next = (z_curr - k_i) / 2^K
+                        let z_next = (z_curr - chunk_value) * two_pow_k_inverse;
+                        region.assign_advice(
+                            || format!("z_{}", i + 1),
+                            self.config.z,
+                            i + 1,
+                            || z_next,
+                        )?
+                    };
+                    z_values.push(z_next.clone());
+                    z = z_next.clone();
+                }
+
+                assert!(z_values.len() == num_of_windows + 1);
+
+                region.constrain_constant(z_values.last().unwrap().cell(), F::zero())?;
+
+                Ok(())
+            },
+        );
+
+        Ok(())
+    }
+}
+
+/// ### Reference  
+pub fn decompose_value<F: FieldExt + PrimeFieldBits, const WINDOW_SIZE: usize>(
+    value: &F,
+    num_of_bits: usize,
+) -> Vec<[bool; WINDOW_SIZE]> {
+    let padding = (WINDOW_SIZE - num_of_bits % WINDOW_SIZE) % WINDOW_SIZE;
+
+    let bits: Vec<bool> = value
+        .to_le_bits()
+        .into_iter()
+        .take(num_of_bits)
+        .chain(std::iter::repeat(false).take(padding))
+        .collect();
+    assert_eq!(bits.len(), num_of_bits + padding);
+
+    bits.chunks_exact(WINDOW_SIZE)
+        .map(|x| {
+            let chunks = [false; WINDOW_SIZE];
+            chunks.copy_from_slice(x);
+            chunks
+        })
+        .collect()
 }
 }