arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/src/select.rs
src/select.rsRaw
  1use crate::prelude::*;
  2use ark_ff::Field;
  3use ark_relations::r1cs::SynthesisError;
  4use ark_std::vec::Vec;
  5/// Generates constraints for selecting between one of two values.
  6pub trait CondSelectGadget<ConstraintF: Field>
  7where
  8    Self: Sized,
  9    Self: Clone,
 10{
 11    /// If `cond == &Boolean::TRUE`, then this returns `true_value`; else,
 12    /// returns `false_value`.
 13    ///
 14    /// # Note
 15    /// `Self::conditionally_select(cond, true_value, false_value)?` can be more
 16    /// succinctly written as `cond.select(&true_value, &false_value)?`.
 17    fn conditionally_select(
 18        cond: &Boolean<ConstraintF>,
 19        true_value: &Self,
 20        false_value: &Self,
 21    ) -> Result<Self, SynthesisError>;
 22
 23    /// Returns an element of `values` whose index in represented by `position`.
 24    /// `position` is an array of boolean that represents an unsigned integer in
 25    /// big endian order.
 26    ///
 27    /// # Example
 28    /// To get the 6th element of `values`, convert unsigned integer 6 (`0b110`)
 29    /// to `position = [True, True, False]`,
 30    /// and call `conditionally_select_power_of_two_vector(position, values)`.
 31    fn conditionally_select_power_of_two_vector(
 32        position: &[Boolean<ConstraintF>],
 33        values: &[Self],
 34    ) -> Result<Self, SynthesisError> {
 35        let m = values.len();
 36        let n = position.len();
 37
 38        // Assert m is a power of 2, and n = log(m)
 39        assert!(m.is_power_of_two());
 40        assert_eq!(1 << n, m);
 41
 42        let mut cur_mux_values = values.to_vec();
 43
 44        // Traverse the evaluation tree from bottom to top in level order traversal.
 45        // This is method 5.1 from https://github.com/mir-protocol/r1cs-workshop/blob/master/workshop.pdf
 46        // TODO: Add method 5.2/5.3
 47        for i in 0..n {
 48            // Size of current layer.
 49            let cur_size = 1 << (n - i);
 50            assert_eq!(cur_mux_values.len(), cur_size);
 51
 52            let mut next_mux_values = Vec::new();
 53            for j in (0..cur_size).step_by(2) {
 54                let cur = Self::conditionally_select(
 55                    &position[n - 1 - i],
 56                    // true case
 57                    &cur_mux_values[j + 1],
 58                    // false case
 59                    &cur_mux_values[j],
 60                )?;
 61                next_mux_values.push(cur);
 62            }
 63            cur_mux_values = next_mux_values;
 64        }
 65
 66        Ok(cur_mux_values[0].clone())
 67    }
 68}
 69
 70/// Performs a lookup in a 4-element table using two bits.
 71pub trait TwoBitLookupGadget<ConstraintF: Field>
 72where
 73    Self: Sized,
 74{
 75    /// The type of values being looked up.
 76    type TableConstant;
 77
 78    /// Interprets the slice `bits` as a two-bit integer `b = bits[0] + (bits[1]
 79    /// << 1)`, and then outputs `constants[b]`.
 80    ///
 81    /// For example, if `bits == [0, 1]`, and `constants == [0, 1, 2, 3]`, this
 82    /// method should output a variable corresponding to `2`.
 83    ///
 84    /// # Panics
 85    ///
 86    /// This method panics if `bits.len() != 2` or `constants.len() != 4`.
 87    fn two_bit_lookup(
 88        bits: &[Boolean<ConstraintF>],
 89        constants: &[Self::TableConstant],
 90    ) -> Result<Self, SynthesisError>;
 91}
 92
 93/// Uses three bits to perform a lookup into a table, where the last bit
 94/// conditionally negates the looked-up value.
 95pub trait ThreeBitCondNegLookupGadget<ConstraintF: Field>
 96where
 97    Self: Sized,
 98{
 99    /// The type of values being looked up.
100    type TableConstant;
101
102    /// Interprets the slice `bits` as a two-bit integer `b = bits[0] + (bits[1]
103    /// << 1)`, and then outputs `constants[b] * c`, where `c = if bits[2] {
104    /// -1 } else { 1 };`.
105    ///
106    /// That is, `bits[2]` conditionally negates the looked-up value.
107    ///
108    /// For example, if `bits == [1, 0, 1]`, and `constants == [0, 1, 2, 3]`,
109    /// this method should output a variable corresponding to `-1`.
110    ///
111    /// # Panics
112    ///
113    /// This method panics if `bits.len() != 3` or `constants.len() != 4`.
114    fn three_bit_cond_neg_lookup(
115        bits: &[Boolean<ConstraintF>],
116        b0b1: &Boolean<ConstraintF>,
117        constants: &[Self::TableConstant],
118    ) -> Result<Self, SynthesisError>;
119}