mirror of
https://github.com/arnaucube/ark-r1cs-std.git
synced 2026-01-11 08:21:30 +01:00
makes API cmp-like
This commit is contained in:
committed by
Pratyush Mishra
parent
ccbb5ef553
commit
7ed38fe4a6
@@ -5,15 +5,114 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use algebra::PrimeField;
|
use algebra::PrimeField;
|
||||||
use r1cs_core::{ConstraintSystem, SynthesisError};
|
use r1cs_core::{ConstraintSystem, SynthesisError};
|
||||||
use std::marker::PhantomData;
|
use std::{
|
||||||
|
cmp::Ordering,
|
||||||
|
marker::PhantomData
|
||||||
|
};
|
||||||
|
|
||||||
pub struct SmallerThanGadget<ConstraintF: PrimeField> {
|
pub struct CmpGadget<ConstraintF: PrimeField> {
|
||||||
constraint_field_type: PhantomData<ConstraintF>,
|
constraint_field_type: PhantomData<ConstraintF>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ConstraintF: PrimeField> SmallerThanGadget<ConstraintF> {
|
impl<ConstraintF: PrimeField> CmpGadget<ConstraintF> {
|
||||||
// the function assumes a and b are known to be <= (p-1)/2
|
fn process_cmp_inputs<CS: ConstraintSystem<ConstraintF>>(
|
||||||
pub fn is_smaller_than<CS: ConstraintSystem<ConstraintF>>(
|
mut cs: CS,
|
||||||
|
a: &FpGadget<ConstraintF>,
|
||||||
|
b: &FpGadget<ConstraintF>,
|
||||||
|
ordering: Ordering,
|
||||||
|
should_also_check_equality: bool,
|
||||||
|
) -> Result<(FpGadget<ConstraintF>, FpGadget<ConstraintF>), SynthesisError> {
|
||||||
|
let left;
|
||||||
|
let right;
|
||||||
|
match ordering {
|
||||||
|
Ordering::Less => { left = a; right = b; }
|
||||||
|
Ordering::Greater => {left = b; right = a; }
|
||||||
|
Ordering::Equal => { return Err(SynthesisError::Unsatisfiable); }
|
||||||
|
};
|
||||||
|
let right_for_check = if should_also_check_equality {
|
||||||
|
right.add_constant(cs.ns(|| "plus one"), &ConstraintF::one())?
|
||||||
|
} else {
|
||||||
|
right.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((left.clone(), right_for_check))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_smaller_than_mod_minus_one_div_two<CS: ConstraintSystem<ConstraintF>>(
|
||||||
|
mut cs: CS,
|
||||||
|
a: &FpGadget<ConstraintF>,
|
||||||
|
) -> Result<(), SynthesisError> {
|
||||||
|
let a_bits = a.to_bits(cs.ns(|| "a to bits"))?;
|
||||||
|
Boolean::enforce_smaller_or_equal_than::<_, _, ConstraintF, _>(
|
||||||
|
cs.ns(|| "enforce smaller than modulus minus one div two"),
|
||||||
|
&a_bits,
|
||||||
|
ConstraintF::modulus_minus_one_div_two(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// this function verifies a and b are <= (p-1)/2
|
||||||
|
pub fn enforce_cmp<CS: ConstraintSystem<ConstraintF>>(
|
||||||
|
mut cs: CS,
|
||||||
|
a: &FpGadget<ConstraintF>,
|
||||||
|
b: &FpGadget<ConstraintF>,
|
||||||
|
ordering: Ordering,
|
||||||
|
should_also_check_equality: bool,
|
||||||
|
) -> Result<(), SynthesisError> {
|
||||||
|
let (left, right) = Self::process_cmp_inputs(cs.ns(|| "process cmp inputs"), a, b, ordering, should_also_check_equality)?;
|
||||||
|
Self::enforce_smaller_than_unchecked(cs.ns(|| "enforce smaller than"), &left, &right)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// this function assumes a and b are known to be <= (p-1)/2
|
||||||
|
pub fn enforce_cmp_unchecked<CS: ConstraintSystem<ConstraintF>>(
|
||||||
|
mut cs: CS,
|
||||||
|
a: &FpGadget<ConstraintF>,
|
||||||
|
b: &FpGadget<ConstraintF>,
|
||||||
|
ordering: Ordering,
|
||||||
|
should_also_check_equality: bool,
|
||||||
|
) -> Result<(), SynthesisError> {
|
||||||
|
let (left, right) = Self::process_cmp_inputs(cs.ns(|| "process cmp inputs"), a, b, ordering, should_also_check_equality)?;
|
||||||
|
Self::enforce_smaller_than(cs.ns(|| "enforce smaller than"), &left, &right)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// this function verifies a and b are <= (p-1)/2
|
||||||
|
pub fn is_cmp<CS: ConstraintSystem<ConstraintF>>(
|
||||||
|
mut cs: CS,
|
||||||
|
a: &FpGadget<ConstraintF>,
|
||||||
|
b: &FpGadget<ConstraintF>,
|
||||||
|
ordering: Ordering,
|
||||||
|
should_also_check_equality: bool,
|
||||||
|
) -> Result<Boolean, SynthesisError> {
|
||||||
|
let (left, right) = Self::process_cmp_inputs(cs.ns(|| "process cmp inputs"), a, b, ordering, should_also_check_equality)?;
|
||||||
|
Self::is_smaller_than(cs.ns(|| "enforce smaller than"), &left, &right)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// this function assumes a and b are known to be <= (p-1)/2
|
||||||
|
pub fn is_cmp_unchecked<CS: ConstraintSystem<ConstraintF>>(
|
||||||
|
mut cs: CS,
|
||||||
|
a: &FpGadget<ConstraintF>,
|
||||||
|
b: &FpGadget<ConstraintF>,
|
||||||
|
ordering: Ordering,
|
||||||
|
should_also_check_equality: bool,
|
||||||
|
) -> Result<Boolean, SynthesisError> {
|
||||||
|
let (left, right) = Self::process_cmp_inputs(cs.ns(|| "process cmp inputs"), a, b, ordering, should_also_check_equality)?;
|
||||||
|
Self::is_smaller_than_unchecked(cs.ns(|| "enforce smaller than"), &left, &right)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// this function verifies a and b are <= (p-1)/2
|
||||||
|
fn is_smaller_than<CS: ConstraintSystem<ConstraintF>>(
|
||||||
|
mut cs: CS,
|
||||||
|
a: &FpGadget<ConstraintF>,
|
||||||
|
b: &FpGadget<ConstraintF>,
|
||||||
|
) -> Result<Boolean, SynthesisError> {
|
||||||
|
Self::check_smaller_than_mod_minus_one_div_two(cs.ns(|| "check a in range"), a)?;
|
||||||
|
Self::check_smaller_than_mod_minus_one_div_two(cs.ns(|| "check b in range"), b)?;
|
||||||
|
Self::is_smaller_than_unchecked(cs.ns(|| "enforce smaller than"), a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// this function assumes a and b are known to be <= (p-1)/2
|
||||||
|
fn is_smaller_than_unchecked<CS: ConstraintSystem<ConstraintF>>(
|
||||||
mut cs: CS,
|
mut cs: CS,
|
||||||
a: &FpGadget<ConstraintF>,
|
a: &FpGadget<ConstraintF>,
|
||||||
b: &FpGadget<ConstraintF>,
|
b: &FpGadget<ConstraintF>,
|
||||||
@@ -26,23 +125,24 @@ impl<ConstraintF: PrimeField> SmallerThanGadget<ConstraintF> {
|
|||||||
Ok(d_bits[d_bits_len - 1])
|
Ok(d_bits[d_bits_len - 1])
|
||||||
}
|
}
|
||||||
|
|
||||||
// the function assumes a and b are known to be <= (p-1)/2
|
/// this function verifies a and b are <= (p-1)/2
|
||||||
pub fn is_smaller_than_or_equal_to<CS: ConstraintSystem<ConstraintF>>(
|
fn enforce_smaller_than<CS: ConstraintSystem<ConstraintF>>(
|
||||||
mut cs: CS,
|
|
||||||
a: &FpGadget<ConstraintF>,
|
|
||||||
b: &FpGadget<ConstraintF>,
|
|
||||||
) -> Result<Boolean, SynthesisError> {
|
|
||||||
let b_plus_one = b.add_constant(cs.ns(|| "plus one"), &ConstraintF::one())?;
|
|
||||||
Self::is_smaller_than(cs.ns(|| "is smaller than"), a, &b_plus_one)
|
|
||||||
}
|
|
||||||
|
|
||||||
// the function assumes a and b are known to be <= (p-1)/2
|
|
||||||
pub fn enforce_smaller_than<CS: ConstraintSystem<ConstraintF>>(
|
|
||||||
mut cs: CS,
|
mut cs: CS,
|
||||||
a: &FpGadget<ConstraintF>,
|
a: &FpGadget<ConstraintF>,
|
||||||
b: &FpGadget<ConstraintF>,
|
b: &FpGadget<ConstraintF>,
|
||||||
) -> Result<(), SynthesisError> {
|
) -> Result<(), SynthesisError> {
|
||||||
let is_smaller_than = Self::is_smaller_than(cs.ns(|| "is smaller than"), a, b)?;
|
Self::check_smaller_than_mod_minus_one_div_two(cs.ns(|| "check a in range"), a)?;
|
||||||
|
Self::check_smaller_than_mod_minus_one_div_two(cs.ns(|| "check b in range"), b)?;
|
||||||
|
Self::enforce_smaller_than_unchecked(cs.ns(|| "enforce smaller than"), a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// this function assumes a and b are known to be <= (p-1)/2
|
||||||
|
fn enforce_smaller_than_unchecked<CS: ConstraintSystem<ConstraintF>>(
|
||||||
|
mut cs: CS,
|
||||||
|
a: &FpGadget<ConstraintF>,
|
||||||
|
b: &FpGadget<ConstraintF>,
|
||||||
|
) -> Result<(), SynthesisError> {
|
||||||
|
let is_smaller_than = Self::is_smaller_than_unchecked(cs.ns(|| "is smaller than"), a, b)?;
|
||||||
cs.enforce(
|
cs.enforce(
|
||||||
|| "enforce smaller than",
|
|| "enforce smaller than",
|
||||||
|_| is_smaller_than.lc(CS::one(), ConstraintF::one()),
|
|_| is_smaller_than.lc(CS::one(), ConstraintF::one()),
|
||||||
@@ -52,54 +152,6 @@ impl<ConstraintF: PrimeField> SmallerThanGadget<ConstraintF> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// the function assumes a and b are known to be <= (p-1)/2
|
|
||||||
pub fn enforce_smaller_than_or_equal_to<CS: ConstraintSystem<ConstraintF>>(
|
|
||||||
mut cs: CS,
|
|
||||||
a: &FpGadget<ConstraintF>,
|
|
||||||
b: &FpGadget<ConstraintF>,
|
|
||||||
) -> Result<(), SynthesisError> {
|
|
||||||
let b_plus_one = b.add_constant(cs.ns(|| "plus one"), &ConstraintF::one())?;
|
|
||||||
Self::enforce_smaller_than(cs.ns(|| "enforce smaller than"), a, &b_plus_one)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enforce_smaller_than_strict<CS: ConstraintSystem<ConstraintF>>(
|
|
||||||
mut cs: CS,
|
|
||||||
a: &FpGadget<ConstraintF>,
|
|
||||||
b: &FpGadget<ConstraintF>,
|
|
||||||
) -> Result<(), SynthesisError> {
|
|
||||||
let a_bits = a.to_bits(cs.ns(|| "a to bits"))?;
|
|
||||||
Boolean::enforce_smaller_or_equal_than::<_, _, ConstraintF, _>(
|
|
||||||
cs.ns(|| "enforce a smaller than modulus minus one div two"),
|
|
||||||
&a_bits,
|
|
||||||
ConstraintF::modulus_minus_one_div_two(),
|
|
||||||
)?;
|
|
||||||
let b_bits = b.to_bits(cs.ns(|| "b to bits"))?;
|
|
||||||
Boolean::enforce_smaller_or_equal_than::<_, _, ConstraintF, _>(
|
|
||||||
cs.ns(|| "enforce b smaller than modulus minus one div two"),
|
|
||||||
&b_bits,
|
|
||||||
ConstraintF::modulus_minus_one_div_two(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let is_smaller_than = Self::is_smaller_than(cs.ns(|| "is smaller than"), a, b)?;
|
|
||||||
cs.enforce(
|
|
||||||
|| "enforce smaller than",
|
|
||||||
|_| is_smaller_than.lc(CS::one(), ConstraintF::one()),
|
|
||||||
|lc| lc + (ConstraintF::one(), CS::one()),
|
|
||||||
|lc| lc + (ConstraintF::one(), CS::one()),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enforce_smaller_than_or_equal_to_strict<CS: ConstraintSystem<ConstraintF>>(
|
|
||||||
mut cs: CS,
|
|
||||||
a: &FpGadget<ConstraintF>,
|
|
||||||
b: &FpGadget<ConstraintF>,
|
|
||||||
) -> Result<(), SynthesisError> {
|
|
||||||
let b_plus_one = b.add_constant(cs.ns(|| "plus one"), &ConstraintF::one())?;
|
|
||||||
Self::enforce_smaller_than_strict(cs.ns(|| "enforce smaller than strict"), a, &b_plus_one)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -108,7 +160,7 @@ mod test {
|
|||||||
use rand_xorshift::XorShiftRng;
|
use rand_xorshift::XorShiftRng;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use super::SmallerThanGadget;
|
use super::CmpGadget;
|
||||||
use crate::{
|
use crate::{
|
||||||
alloc::AllocGadget, fields::fp::FpGadget, test_constraint_system::TestConstraintSystem,
|
alloc::AllocGadget, fields::fp::FpGadget, test_constraint_system::TestConstraintSystem,
|
||||||
};
|
};
|
||||||
@@ -141,30 +193,38 @@ mod test {
|
|||||||
|
|
||||||
match a.cmp(&b) {
|
match a.cmp(&b) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
SmallerThanGadget::<Fr>::enforce_smaller_than_strict(
|
CmpGadget::<Fr>::enforce_cmp(
|
||||||
cs.ns(|| "smaller than test"),
|
cs.ns(|| "smaller than test"),
|
||||||
&a_var,
|
&a_var,
|
||||||
&b_var,
|
&b_var,
|
||||||
|
Ordering::Less,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
SmallerThanGadget::<Fr>::enforce_smaller_than_or_equal_to_strict(
|
CmpGadget::<Fr>::enforce_cmp(
|
||||||
cs.ns(|| "smaller than test 2"),
|
cs.ns(|| "smaller than test 2"),
|
||||||
&a_var,
|
&a_var,
|
||||||
&b_var,
|
&b_var,
|
||||||
|
Ordering::Less,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
},
|
},
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
SmallerThanGadget::<Fr>::enforce_smaller_than_strict(
|
CmpGadget::<Fr>::enforce_cmp(
|
||||||
cs.ns(|| "smaller than test"),
|
cs.ns(|| "smaller than test"),
|
||||||
&b_var,
|
|
||||||
&a_var,
|
&a_var,
|
||||||
|
&b_var,
|
||||||
|
Ordering::Greater,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
SmallerThanGadget::<Fr>::enforce_smaller_than_or_equal_to_strict(
|
CmpGadget::<Fr>::enforce_cmp(
|
||||||
cs.ns(|| "smaller than test 2"),
|
cs.ns(|| "smaller than test 2"),
|
||||||
&b_var,
|
|
||||||
&a_var,
|
&a_var,
|
||||||
|
&b_var,
|
||||||
|
Ordering::Greater,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
},
|
},
|
||||||
@@ -186,30 +246,38 @@ mod test {
|
|||||||
|
|
||||||
match b.cmp(&a) {
|
match b.cmp(&a) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
SmallerThanGadget::<Fr>::enforce_smaller_than_strict(
|
CmpGadget::<Fr>::enforce_cmp(
|
||||||
cs.ns(|| "smaller than test"),
|
cs.ns(|| "smaller than test"),
|
||||||
&a_var,
|
&a_var,
|
||||||
&b_var,
|
&b_var,
|
||||||
|
Ordering::Less,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
SmallerThanGadget::<Fr>::enforce_smaller_than_or_equal_to_strict(
|
CmpGadget::<Fr>::enforce_cmp(
|
||||||
cs.ns(|| "smaller than test 2"),
|
cs.ns(|| "smaller than test 2"),
|
||||||
&a_var,
|
&a_var,
|
||||||
&b_var,
|
&b_var,
|
||||||
|
Ordering::Less,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
},
|
},
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
SmallerThanGadget::<Fr>::enforce_smaller_than_strict(
|
CmpGadget::<Fr>::enforce_cmp(
|
||||||
cs.ns(|| "smaller than test"),
|
cs.ns(|| "smaller than test"),
|
||||||
&b_var,
|
|
||||||
&a_var,
|
&a_var,
|
||||||
|
&b_var,
|
||||||
|
Ordering::Greater,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
SmallerThanGadget::<Fr>::enforce_smaller_than_or_equal_to(
|
CmpGadget::<Fr>::enforce_cmp(
|
||||||
cs.ns(|| "smaller than test 2"),
|
cs.ns(|| "smaller than test 2"),
|
||||||
&b_var,
|
|
||||||
&a_var,
|
&a_var,
|
||||||
|
&b_var,
|
||||||
|
Ordering::Greater,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
},
|
},
|
||||||
@@ -223,10 +291,12 @@ mod test {
|
|||||||
let mut cs = TestConstraintSystem::<Fr>::new();
|
let mut cs = TestConstraintSystem::<Fr>::new();
|
||||||
let a = rand_in_range(&mut rng);
|
let a = rand_in_range(&mut rng);
|
||||||
let a_var = FpGadget::<Fr>::alloc(cs.ns(|| "a"), || Ok(a)).unwrap();
|
let a_var = FpGadget::<Fr>::alloc(cs.ns(|| "a"), || Ok(a)).unwrap();
|
||||||
SmallerThanGadget::<Fr>::enforce_smaller_than_strict(
|
CmpGadget::<Fr>::enforce_cmp(
|
||||||
cs.ns(|| "smaller than test"),
|
cs.ns(|| "smaller than test"),
|
||||||
&a_var,
|
&a_var,
|
||||||
&a_var,
|
&a_var,
|
||||||
|
Ordering::Less,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -237,10 +307,12 @@ mod test {
|
|||||||
let mut cs = TestConstraintSystem::<Fr>::new();
|
let mut cs = TestConstraintSystem::<Fr>::new();
|
||||||
let a = rand_in_range(&mut rng);
|
let a = rand_in_range(&mut rng);
|
||||||
let a_var = FpGadget::<Fr>::alloc(cs.ns(|| "a"), || Ok(a)).unwrap();
|
let a_var = FpGadget::<Fr>::alloc(cs.ns(|| "a"), || Ok(a)).unwrap();
|
||||||
SmallerThanGadget::<Fr>::enforce_smaller_than_or_equal_to(
|
CmpGadget::<Fr>::enforce_cmp(
|
||||||
cs.ns(|| "smaller than or equal to test"),
|
cs.ns(|| "smaller than or equal to test"),
|
||||||
&a_var,
|
&a_var,
|
||||||
&a_var,
|
&a_var,
|
||||||
|
Ordering::Less,
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ pub mod pairing;
|
|||||||
pub mod alloc;
|
pub mod alloc;
|
||||||
pub mod eq;
|
pub mod eq;
|
||||||
pub mod select;
|
pub mod select;
|
||||||
pub mod smaller_than;
|
pub mod cmp;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
@@ -74,6 +74,7 @@ pub mod prelude {
|
|||||||
instantiated::*,
|
instantiated::*,
|
||||||
pairing::PairingGadget,
|
pairing::PairingGadget,
|
||||||
select::*,
|
select::*,
|
||||||
|
cmp::CmpGadget,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user