mirror of
https://github.com/arnaucube/ark-r1cs-std.git
synced 2026-01-09 23:41:33 +01:00
Add Mux gadget (#48)
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
### Breaking changes
|
### Breaking changes
|
||||||
- #12 Make the output of the `ToBitsGadget` impl for `FpVar` fixed-size
|
- #12 Make the output of the `ToBitsGadget` impl for `FpVar` fixed-size
|
||||||
|
- #48 Add `Clone` trait bound to `CondSelectGadget`.
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
|
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
- #35 Construct a `FpVar` from bits
|
- #35 Construct a `FpVar` from bits
|
||||||
- #36 Implement `ToConstraintFieldGadget` for `Vec<Uint8>`
|
- #36 Implement `ToConstraintFieldGadget` for `Vec<Uint8>`
|
||||||
- #40, #43 Faster scalar multiplication for Short Weierstrass curves by relying on affine formulae
|
- #40, #43 Faster scalar multiplication for Short Weierstrass curves by relying on affine formulae
|
||||||
|
- #46 Add mux gadget as an auto-impl in `CondSelectGadget` to support random access of an array
|
||||||
|
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
- #8 Fix bug in `three_bit_cond_neg_lookup` when using a constant lookup bit
|
- #8 Fix bug in `three_bit_cond_neg_lookup` when using a constant lookup bit
|
||||||
|
|||||||
@@ -503,4 +503,42 @@ mod test {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uint8_random_access() {
|
||||||
|
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
|
||||||
|
|
||||||
|
for _ in 0..100 {
|
||||||
|
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||||
|
|
||||||
|
// value array
|
||||||
|
let values: Vec<u8> = (0..128).map(|_| rng.gen()).collect();
|
||||||
|
let values_const: Vec<UInt8<Fr>> = values.iter().map(|x| UInt8::constant(*x)).collect();
|
||||||
|
|
||||||
|
// index array
|
||||||
|
let position: Vec<bool> = (0..7).map(|_| rng.gen()).collect();
|
||||||
|
let position_var: Vec<Boolean<Fr>> = position
|
||||||
|
.iter()
|
||||||
|
.map(|b| {
|
||||||
|
Boolean::new_witness(ark_relations::ns!(cs, "index_arr_element"), || Ok(*b))
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// index
|
||||||
|
let mut index = 0;
|
||||||
|
for x in position {
|
||||||
|
index *= 2;
|
||||||
|
index += if x { 1 } else { 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
UInt8::conditionally_select_power_of_two_vector(&position_var, &values_const)
|
||||||
|
.unwrap()
|
||||||
|
.value()
|
||||||
|
.unwrap(),
|
||||||
|
values[index]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use ark_ff::Field;
|
use ark_ff::Field;
|
||||||
use ark_relations::r1cs::SynthesisError;
|
use ark_relations::r1cs::SynthesisError;
|
||||||
|
use ark_std::vec::Vec;
|
||||||
/// Generates constraints for selecting between one of two values.
|
/// Generates constraints for selecting between one of two values.
|
||||||
pub trait CondSelectGadget<ConstraintF: Field>
|
pub trait CondSelectGadget<ConstraintF: Field>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
Self: Clone,
|
||||||
{
|
{
|
||||||
/// If `cond == &Boolean::TRUE`, then this returns `true_value`; else,
|
/// If `cond == &Boolean::TRUE`, then this returns `true_value`; else,
|
||||||
/// returns `false_value`.
|
/// returns `false_value`.
|
||||||
@@ -18,6 +19,50 @@ where
|
|||||||
true_value: &Self,
|
true_value: &Self,
|
||||||
false_value: &Self,
|
false_value: &Self,
|
||||||
) -> Result<Self, SynthesisError>;
|
) -> Result<Self, SynthesisError>;
|
||||||
|
|
||||||
|
/// Returns an element of `values` whose index in represented by `position`.
|
||||||
|
/// `position` is an array of boolean that represents an unsigned integer in big endian order.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// To get the 6th element of `values`, convert unsigned integer 6 (`0b110`) to `position = [True, True, False]`,
|
||||||
|
/// and call `conditionally_select_power_of_two_vector(position, values)`.
|
||||||
|
fn conditionally_select_power_of_two_vector(
|
||||||
|
position: &[Boolean<ConstraintF>],
|
||||||
|
values: &[Self],
|
||||||
|
) -> Result<Self, SynthesisError> {
|
||||||
|
let m = values.len();
|
||||||
|
let n = position.len();
|
||||||
|
|
||||||
|
// Assert m is a power of 2, and n = log(m)
|
||||||
|
assert!(m.is_power_of_two());
|
||||||
|
assert_eq!(1 << n, m);
|
||||||
|
|
||||||
|
let mut cur_mux_values = values.to_vec();
|
||||||
|
|
||||||
|
// Traverse the evaluation tree from bottom to top in level order traversal.
|
||||||
|
// This is method 5.1 from https://github.com/mir-protocol/r1cs-workshop/blob/master/workshop.pdf
|
||||||
|
// TODO: Add method 5.2/5.3
|
||||||
|
for i in 0..n {
|
||||||
|
// Size of current layer.
|
||||||
|
let cur_size = 1 << (n - i);
|
||||||
|
assert_eq!(cur_mux_values.len(), cur_size);
|
||||||
|
|
||||||
|
let mut next_mux_values = Vec::new();
|
||||||
|
for j in (0..cur_size).step_by(2) {
|
||||||
|
let cur = Self::conditionally_select(
|
||||||
|
&position[n - 1 - i],
|
||||||
|
// true case
|
||||||
|
&cur_mux_values[j + 1],
|
||||||
|
// false case
|
||||||
|
&cur_mux_values[j],
|
||||||
|
)?;
|
||||||
|
next_mux_values.push(cur);
|
||||||
|
}
|
||||||
|
cur_mux_values = next_mux_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(cur_mux_values[0].clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs a lookup in a 4-element table using two bits.
|
/// Performs a lookup in a 4-element table using two bits.
|
||||||
|
|||||||
Reference in New Issue
Block a user