Browse Source

makes API cmp-like

master
Kobi Gurkan 4 years ago
committed by Pratyush Mishra
parent
commit
7ed38fe4a6
2 changed files with 143 additions and 70 deletions
  1. +141
    -69
      r1cs-std/src/cmp.rs
  2. +2
    -1
      r1cs-std/src/lib.rs

r1cs-std/src/smaller_than.rs → r1cs-std/src/cmp.rs

@ -5,83 +5,144 @@ 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> {
// the function assumes a and b are known to be <= (p-1)/2
pub fn is_smaller_than<CS: ConstraintSystem<ConstraintF>>(
impl<ConstraintF: PrimeField> CmpGadget<ConstraintF> {
fn process_cmp_inputs<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, mut cs: CS,
a: &FpGadget<ConstraintF>, a: &FpGadget<ConstraintF>,
b: &FpGadget<ConstraintF>, b: &FpGadget<ConstraintF>,
ordering: Ordering,
should_also_check_equality: bool,
) -> Result<Boolean, SynthesisError> { ) -> Result<Boolean, SynthesisError> {
let two = ConstraintF::one() + ConstraintF::one();
let d0 = a.sub(cs.ns(|| "a - b"), b)?;
let d = d0.mul_by_constant(cs.ns(|| "mul 2"), &two)?;
let d_bits = d.to_bits_strict(cs.ns(|| "d to bits"))?;
let d_bits_len = d_bits.len();
Ok(d_bits[d_bits_len - 1])
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)
} }
// the function assumes a and b are known to be <= (p-1)/2
pub fn is_smaller_than_or_equal_to<CS: ConstraintSystem<ConstraintF>>(
/// this function assumes a and b are known to be <= (p-1)/2
pub fn is_cmp_unchecked<CS: ConstraintSystem<ConstraintF>>(
mut cs: CS, mut cs: CS,
a: &FpGadget<ConstraintF>, a: &FpGadget<ConstraintF>,
b: &FpGadget<ConstraintF>, b: &FpGadget<ConstraintF>,
ordering: Ordering,
should_also_check_equality: bool,
) -> Result<Boolean, SynthesisError> { ) -> 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)
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)
} }
// the function assumes a and b are known to be <= (p-1)/2
pub fn enforce_smaller_than<CS: ConstraintSystem<ConstraintF>>(
/// this function verifies a and b are <= (p-1)/2
fn is_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> {
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()),
);
) -> 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)
}
Ok(())
/// this function assumes a and b are known to be <= (p-1)/2
fn is_smaller_than_unchecked<CS: ConstraintSystem<ConstraintF>>(
mut cs: CS,
a: &FpGadget<ConstraintF>,
b: &FpGadget<ConstraintF>,
) -> Result<Boolean, SynthesisError> {
let two = ConstraintF::one() + ConstraintF::one();
let d0 = a.sub(cs.ns(|| "a - b"), b)?;
let d = d0.mul_by_constant(cs.ns(|| "mul 2"), &two)?;
let d_bits = d.to_bits_strict(cs.ns(|| "d to bits"))?;
let d_bits_len = d_bits.len();
Ok(d_bits[d_bits_len - 1])
} }
// the function assumes a and b are known to be <= (p-1)/2
pub fn enforce_smaller_than_or_equal_to<CS: ConstraintSystem<ConstraintF>>(
/// this function verifies a and b are <= (p-1)/2
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 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)
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)
} }
pub fn enforce_smaller_than_strict<CS: ConstraintSystem<ConstraintF>>(
/// this function assumes a and b are known to be <= (p-1)/2
fn enforce_smaller_than_unchecked<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 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)?;
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()),
@ -91,15 +152,6 @@ impl SmallerThanGadget {
Ok(()) 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();

+ 2
- 1
r1cs-std/src/lib.rs

@ -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,
}; };
} }

Loading…
Cancel
Save