-
Notifications
You must be signed in to change notification settings - Fork 66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hybrid method for random access/conditional selection from 2^k values #119
base: master
Are you sure you want to change the base?
Changes from 15 commits
39c111e
e5291a0
c0e6ca2
6c93fb6
3e817f2
e7db1c0
e60df9d
d9dd651
f5617fa
80dfddf
aff5fe0
bd5eb43
0952ab0
995463f
db7b97d
f7e8abc
d5f3a34
6939d3f
1ea679d
760b045
3ca576b
b5f88b8
777da9c
6c4e56f
74ce483
f165d68
2f79c48
7ce86de
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -425,8 +425,9 @@ impl<F: PrimeField> AllocatedFp<F> { | |
// The high level logic is as follows: | ||
// We want to check that self - other != 0. We do this by checking that | ||
// (self - other).inverse() exists. In more detail, we check the following: | ||
// If `should_enforce == true`, then we set `multiplier = (self - other).inverse()`, | ||
// and check that (self - other) * multiplier == 1. (i.e., that the inverse exists) | ||
// If `should_enforce == true`, then we set `multiplier = (self - | ||
// other).inverse()`, and check that (self - other) * multiplier == 1. | ||
// (i.e., that the inverse exists) | ||
// | ||
// If `should_enforce == false`, then we set `multiplier == 0`, and check that | ||
// (self - other) * 0 == 0, which is always satisfied. | ||
|
@@ -978,6 +979,24 @@ impl<F: PrimeField> CondSelectGadget<F> for FpVar<F> { | |
}, | ||
} | ||
} | ||
|
||
fn add_lc( | ||
val: &Self, | ||
lc: &LinearCombination<F>, | ||
) -> Result<LinearCombination<F>, SynthesisError> { | ||
let root: LinearCombination<F> = LinearCombination::zero(); | ||
let v = val.value()?; | ||
Ok(root + (v, lc)) | ||
} | ||
|
||
fn allocate_to_lc( | ||
var: Variable, | ||
val: &Self, | ||
cs: &ConstraintSystemRef<F>, | ||
) -> Result<Self, SynthesisError> { | ||
let v = val.value()?; | ||
Ok(AllocatedFp::new(Some(v), var, cs.clone()).into()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm not sure what this method is doing; is it just a clone of the variable? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a chance I'm doing something wrong here. The way I understand it is that I have an LC that corresponds to some Perhaps the method name isn't great... what I thought of doing was, as mentioned in the PR description, adding a trait bound for |
||
} | ||
} | ||
|
||
/// Uses two bits to perform a lookup into a table | ||
|
@@ -1067,12 +1086,14 @@ impl<'a, F: PrimeField> Sum<&'a FpVar<F>> for FpVar<F> { | |
mod test { | ||
use crate::{ | ||
alloc::{AllocVar, AllocationMode}, | ||
boolean::Boolean, | ||
eq::EqGadget, | ||
fields::fp::FpVar, | ||
select::CondSelectGadget, | ||
R1CSVar, | ||
}; | ||
use ark_relations::r1cs::ConstraintSystem; | ||
use ark_std::{UniformRand, Zero}; | ||
use ark_std::{rand::Rng, UniformRand, Zero}; | ||
use ark_test_curves::bls12_381::Fr; | ||
|
||
#[test] | ||
|
@@ -1105,4 +1126,42 @@ mod test { | |
assert!(cs.is_satisfied().unwrap()); | ||
assert_eq!(sum.value().unwrap(), sum_expected); | ||
} | ||
|
||
#[test] | ||
fn test_fpvar_random_access() { | ||
let mut rng = ark_std::test_rng(); | ||
|
||
for _ in 0..100 { | ||
let cs = ConstraintSystem::<Fr>::new_ref(); | ||
|
||
// value array | ||
let values: Vec<Fr> = (0..128).map(|_| rng.gen()).collect(); | ||
let values_const: Vec<FpVar<Fr>> = values.iter().map(|x| FpVar::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!( | ||
FpVar::conditionally_select_power_of_two_vector(&position_var, &values_const) | ||
.unwrap() | ||
.value() | ||
.unwrap(), | ||
values[index] | ||
) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why doesn't it suffice to just use addition on
FpVar
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or,
sum
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I simplified this slightly.