Merge pull request #73 from AleoHQ/feature/comparator

Feature/comparator
This commit is contained in:
Collin Chin 2020-07-02 22:04:48 -07:00 committed by GitHub
commit 14adaaa820
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 249 additions and 122 deletions

1
Cargo.lock generated
View File

@ -607,7 +607,6 @@ dependencies = [
"serde", "serde",
"snarkos-errors", "snarkos-errors",
"snarkos-models", "snarkos-models",
"thiserror",
] ]
[[package]] [[package]]

View File

@ -0,0 +1,28 @@
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
curves::Field,
gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean},
};
pub trait EvaluateLtGadget<F: Field> {
fn less_than<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError>;
}
// implementing `EvaluateLtGadget` will implement `ComparatorGadget`
pub trait ComparatorGadget<F: Field>
where
Self: EvaluateLtGadget<F>,
{
fn greater_than<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
other.less_than(cs, self)
}
fn less_than_or_equal<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
let is_gt = self.greater_than(cs, other)?;
Ok(is_gt.not())
}
fn greater_than_or_equal<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
other.less_than_or_equal(cs, self)
}
}

View File

@ -1,6 +1,7 @@
//! Methods to enforce constraints on expressions in a resolved Leo program. //! Methods to enforce constraints on expressions in a resolved Leo program.
use crate::{ use crate::{
comparator::{ComparatorGadget, EvaluateLtGadget},
constraints::{ constraints::{
boolean::{enforce_and, enforce_or, evaluate_not, new_bool_constant}, boolean::{enforce_and, enforce_or, evaluate_not, new_bool_constant},
new_scope, new_scope,
@ -11,13 +12,13 @@ use crate::{
errors::ExpressionError, errors::ExpressionError,
FieldType, FieldType,
GroupType, GroupType,
Integer,
}; };
use leo_types::{ use leo_types::{
CircuitFieldDefinition, CircuitFieldDefinition,
CircuitMember, CircuitMember,
Expression, Expression,
Identifier, Identifier,
Integer,
IntegerType, IntegerType,
RangeOrExpression, RangeOrExpression,
Span, Span,
@ -76,11 +77,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Ok(ConstrainedValue::Integer(num_1.add(cs, num_2, span)?)) Ok(ConstrainedValue::Integer(num_1.add(cs, num_2, span)?))
} }
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
Ok(ConstrainedValue::Field(fe_1.add(cs, &fe_2, span)?)) Ok(ConstrainedValue::Field(field_1.add(cs, &field_2, span)?))
} }
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => { (ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => {
Ok(ConstrainedValue::Group(ge_1.add(cs, &ge_2, span)?)) Ok(ConstrainedValue::Group(point_1.add(cs, &point_2, span)?))
} }
(ConstrainedValue::Unresolved(string), val_2) => { (ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
@ -108,11 +109,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Ok(ConstrainedValue::Integer(num_1.sub(cs, num_2, span)?)) Ok(ConstrainedValue::Integer(num_1.sub(cs, num_2, span)?))
} }
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
Ok(ConstrainedValue::Field(fe_1.sub(cs, &fe_2, span)?)) Ok(ConstrainedValue::Field(field_1.sub(cs, &field_2, span)?))
} }
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => { (ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => {
Ok(ConstrainedValue::Group(ge_1.sub(cs, &ge_2, span)?)) Ok(ConstrainedValue::Group(point_1.sub(cs, &point_2, span)?))
} }
(ConstrainedValue::Unresolved(string), val_2) => { (ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
@ -140,8 +141,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Ok(ConstrainedValue::Integer(num_1.mul(cs, num_2, span)?)) Ok(ConstrainedValue::Integer(num_1.mul(cs, num_2, span)?))
} }
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
Ok(ConstrainedValue::Field(fe_1.mul(cs, &fe_2, span)?)) Ok(ConstrainedValue::Field(field_1.mul(cs, &field_2, span)?))
} }
(ConstrainedValue::Unresolved(string), val_2) => { (ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
@ -171,8 +172,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
Ok(ConstrainedValue::Integer(num_1.div(cs, num_2, span)?)) Ok(ConstrainedValue::Integer(num_1.div(cs, num_2, span)?))
} }
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
Ok(ConstrainedValue::Field(fe_1.div(cs, &fe_2, span)?)) Ok(ConstrainedValue::Field(field_1.div(cs, &field_2, span)?))
} }
(ConstrainedValue::Unresolved(string), val_2) => { (ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
@ -233,11 +234,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
num_1.evaluate_equal(unique_namespace, &num_2) num_1.evaluate_equal(unique_namespace, &num_2)
} }
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
fe_1.evaluate_equal(unique_namespace, &fe_2) field_1.evaluate_equal(unique_namespace, &field_2)
} }
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => { (ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => {
ge_1.evaluate_equal(unique_namespace, &ge_2) point_1.evaluate_equal(unique_namespace, &point_2)
} }
(ConstrainedValue::Unresolved(string), val_2) => { (ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
@ -256,133 +257,157 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
}; };
let boolean = let boolean =
constraint_result.map_err(|e| ExpressionError::cannot_enforce(format!("evaluate equals"), e, span))?; constraint_result.map_err(|e| ExpressionError::cannot_enforce(format!("evaluate equal"), e, span))?;
Ok(ConstrainedValue::Boolean(boolean)) Ok(ConstrainedValue::Boolean(boolean))
} }
//TODO: unsafe for allocated values fn evaluate_ge_expression<CS: ConstraintSystem<F>>(
fn evaluate_ge_expression(
&mut self, &mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>, left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>, right: ConstrainedValue<F, G>,
span: Span, span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> { ) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) { let mut unique_namespace = cs.ns(|| format!("evaluate {} >= {} {}:{}", left, right, span.line, span.start));
let constraint_result = match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
let result = num_1.ge(&num_2); num_1.greater_than_or_equal(unique_namespace, &num_2)
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
} }
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
let result = fe_1.ge(&fe_2); field_1.greater_than_or_equal(unique_namespace, &field_2)
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
} }
(ConstrainedValue::Unresolved(string), val_2) => { (ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
self.evaluate_ge_expression(val_1, val_2, span) return self.evaluate_ge_expression(&mut unique_namespace, val_1, val_2, span);
} }
(val_1, ConstrainedValue::Unresolved(string)) => { (val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
self.evaluate_ge_expression(val_1, val_2, span) return self.evaluate_ge_expression(&mut unique_namespace, val_1, val_2, span);
} }
(val_1, val_2) => Err(ExpressionError::incompatible_types( (val_1, val_2) => {
format!("{} >= {}", val_1, val_2), return Err(ExpressionError::incompatible_types(
span, format!("{} >= {}", val_1, val_2),
)), span,
} ));
}
};
let boolean = constraint_result
.map_err(|e| ExpressionError::cannot_enforce(format!("evaluate greater than or equal"), e, span))?;
Ok(ConstrainedValue::Boolean(boolean))
} }
//TODO: unsafe for allocated values fn evaluate_gt_expression<CS: ConstraintSystem<F>>(
fn evaluate_gt_expression(
&mut self, &mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>, left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>, right: ConstrainedValue<F, G>,
span: Span, span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> { ) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) { let mut unique_namespace = cs.ns(|| format!("evaluate {} > {} {}:{}", left, right, span.line, span.start));
let constraint_result = match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
let result = num_1.gt(&num_2); num_1.greater_than(unique_namespace, &num_2)
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
} }
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
let result = fe_1.gt(&fe_2); field_1.greater_than(unique_namespace, &field_2)
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
} }
(ConstrainedValue::Unresolved(string), val_2) => { (ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
self.evaluate_gt_expression(val_1, val_2, span) return self.evaluate_gt_expression(&mut unique_namespace, val_1, val_2, span);
} }
(val_1, ConstrainedValue::Unresolved(string)) => { (val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
self.evaluate_gt_expression(val_1, val_2, span) return self.evaluate_gt_expression(&mut unique_namespace, val_1, val_2, span);
} }
(val_1, val_2) => Err(ExpressionError::incompatible_types( (val_1, val_2) => {
format!("{} > {}", val_1, val_2), return Err(ExpressionError::incompatible_types(
span, format!("{} > {}", val_1, val_2),
)), span,
} ));
}
};
let boolean = constraint_result
.map_err(|e| ExpressionError::cannot_enforce(format!("evaluate greater than"), e, span))?;
Ok(ConstrainedValue::Boolean(boolean))
} }
//TODO: unsafe for allocated values fn evaluate_le_expression<CS: ConstraintSystem<F>>(
fn evaluate_le_expression(
&mut self, &mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>, left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>, right: ConstrainedValue<F, G>,
span: Span, span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> { ) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) { let mut unique_namespace = cs.ns(|| format!("evaluate {} <= {} {}:{}", left, right, span.line, span.start));
let constraint_result = match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
let result = num_1.le(&num_2); num_1.less_than_or_equal(unique_namespace, &num_2)
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
} }
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
let result = fe_1.le(&fe_2); field_1.less_than_or_equal(unique_namespace, &field_2)
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
} }
(ConstrainedValue::Unresolved(string), val_2) => { (ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
self.evaluate_le_expression(val_1, val_2, span) return self.evaluate_le_expression(&mut unique_namespace, val_1, val_2, span);
} }
(val_1, ConstrainedValue::Unresolved(string)) => { (val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
self.evaluate_le_expression(val_1, val_2, span) return self.evaluate_le_expression(&mut unique_namespace, val_1, val_2, span);
} }
(val_1, val_2) => Err(ExpressionError::incompatible_types( (val_1, val_2) => {
format!("{} <= {}", val_1, val_2), return Err(ExpressionError::incompatible_types(
span, format!("{} <= {}", val_1, val_2),
)), span,
} ));
}
};
let boolean = constraint_result
.map_err(|e| ExpressionError::cannot_enforce(format!("evaluate less than or equal"), e, span))?;
Ok(ConstrainedValue::Boolean(boolean))
} }
//TODO: unsafe for allocated values fn evaluate_lt_expression<CS: ConstraintSystem<F>>(
fn evaluate_lt_expression(
&mut self, &mut self,
cs: &mut CS,
left: ConstrainedValue<F, G>, left: ConstrainedValue<F, G>,
right: ConstrainedValue<F, G>, right: ConstrainedValue<F, G>,
span: Span, span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> { ) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) { let mut unique_namespace = cs.ns(|| format!("evaluate {} < {} {}:{}", left, right, span.line, span.start));
let constraint_result = match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
let result = num_1.lt(&num_2); num_1.less_than(unique_namespace, &num_2)
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
} }
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => { (ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
let result = fe_1.lt(&fe_2); field_1.less_than(unique_namespace, &field_2)
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
} }
(ConstrainedValue::Unresolved(string), val_2) => { (ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
self.evaluate_lt_expression(val_1, val_2, span) return self.evaluate_lt_expression(&mut unique_namespace, val_1, val_2, span);
} }
(val_1, ConstrainedValue::Unresolved(string)) => { (val_1, ConstrainedValue::Unresolved(string)) => {
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?; let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
self.evaluate_lt_expression(val_1, val_2, span) return self.evaluate_lt_expression(&mut unique_namespace, val_1, val_2, span);
} }
(val_1, val_2) => Err(ExpressionError::incompatible_types( (val_1, val_2) => {
format!("{} < {}", val_1, val_2,), return Err(ExpressionError::incompatible_types(
span, format!("{} < {}", val_1, val_2),
)), span,
} ));
}
};
let boolean =
constraint_result.map_err(|e| ExpressionError::cannot_enforce(format!("evaluate less than"), e, span))?;
Ok(ConstrainedValue::Boolean(boolean))
} }
/// Enforce ternary conditional expression /// Enforce ternary conditional expression
@ -1029,7 +1054,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
span.clone(), span.clone(),
)?; )?;
Ok(self.evaluate_ge_expression(resolved_left, resolved_right, span)?) Ok(self.evaluate_ge_expression(cs, resolved_left, resolved_right, span)?)
} }
Expression::Gt(left, right, span) => { Expression::Gt(left, right, span) => {
let (resolved_left, resolved_right) = self.enforce_binary_expression( let (resolved_left, resolved_right) = self.enforce_binary_expression(
@ -1042,7 +1067,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
span.clone(), span.clone(),
)?; )?;
Ok(self.evaluate_gt_expression(resolved_left, resolved_right, span)?) Ok(self.evaluate_gt_expression(cs, resolved_left, resolved_right, span)?)
} }
Expression::Le(left, right, span) => { Expression::Le(left, right, span) => {
let (resolved_left, resolved_right) = self.enforce_binary_expression( let (resolved_left, resolved_right) = self.enforce_binary_expression(
@ -1055,7 +1080,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
span.clone(), span.clone(),
)?; )?;
Ok(self.evaluate_le_expression(resolved_left, resolved_right, span)?) Ok(self.evaluate_le_expression(cs, resolved_left, resolved_right, span)?)
} }
Expression::Lt(left, right, span) => { Expression::Lt(left, right, span) => {
let (resolved_left, resolved_right) = self.enforce_binary_expression( let (resolved_left, resolved_right) = self.enforce_binary_expression(
@ -1068,7 +1093,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
span.clone(), span.clone(),
)?; )?;
Ok(self.evaluate_lt_expression(resolved_left, resolved_right, span)?) Ok(self.evaluate_lt_expression(cs, resolved_left, resolved_right, span)?)
} }
// Conditionals // Conditionals

View File

@ -12,8 +12,10 @@ use crate::{
}, },
errors::{FunctionError, StatementError}, errors::{FunctionError, StatementError},
GroupType, GroupType,
Integer,
}; };
use leo_types::{Expression, Function, InputValue, Integer, Span, Type};
use leo_types::{Expression, Function, InputValue, Span, Type};
use snarkos_models::{ use snarkos_models::{
curves::{Field, PrimeField}, curves::{Field, PrimeField},

View File

@ -1,6 +1,6 @@
//! Conversion of integer declarations to constraints in Leo. //! Conversion of integer declarations to constraints in Leo.
use crate::{errors::IntegerError, ComparatorGadget, EvaluateLtGadget};
use crate::{errors::IntegerError, InputValue, IntegerType, Span}; use leo_types::{InputValue, IntegerType, Span};
use snarkos_errors::gadgets::SynthesisError; use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{ use snarkos_models::{
@ -88,6 +88,16 @@ impl Integer {
Ok(value as usize) Ok(value as usize)
} }
pub fn to_bits_le(&self) -> Vec<Boolean> {
match self {
Integer::U8(num) => num.bits.clone(),
Integer::U16(num) => num.bits.clone(),
Integer::U32(num) => num.bits.clone(),
Integer::U64(num) => num.bits.clone(),
Integer::U128(num) => num.bits.clone(),
}
}
pub fn get_type(&self) -> IntegerType { pub fn get_type(&self) -> IntegerType {
match self { match self {
Integer::U8(_u8) => IntegerType::U8, Integer::U8(_u8) => IntegerType::U8,
@ -435,6 +445,42 @@ impl<F: Field + PrimeField> EvaluateEqGadget<F> for Integer {
} }
} }
impl<F: Field + PrimeField> EvaluateLtGadget<F> for Integer {
fn less_than<CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
if self.to_bits_le().len() != other.to_bits_le().len() {
return Err(SynthesisError::Unsatisfiable);
}
for (i, (self_bit, other_bit)) in self
.to_bits_le()
.iter()
.rev()
.zip(other.to_bits_le().iter().rev())
.enumerate()
{
// is_greater = a & !b
// only true when a > b
let is_greater = Boolean::and(cs.ns(|| format!("a and not b [{}]", i)), self_bit, &other_bit.not())?;
// is_less = !a & b
// only true when a < b
let is_less = Boolean::and(cs.ns(|| format!("not a and b [{}]", i)), &self_bit.not(), other_bit)?;
if is_greater.get_value().unwrap() {
return Ok(is_greater.not());
} else if is_less.get_value().unwrap() {
return Ok(is_less);
} else if i == self.to_bits_le().len() - 1 {
return Ok(is_less);
}
}
Err(SynthesisError::Unsatisfiable)
}
}
impl<F: Field + PrimeField> ComparatorGadget<F> for Integer {}
impl<F: Field + PrimeField> EqGadget<F> for Integer {} impl<F: Field + PrimeField> EqGadget<F> for Integer {}
impl<F: Field + PrimeField> ConditionalEqGadget<F> for Integer { impl<F: Field + PrimeField> ConditionalEqGadget<F> for Integer {

View File

@ -2,6 +2,9 @@
pub mod boolean; pub mod boolean;
pub(crate) mod comparator;
pub(crate) use comparator::*;
pub mod function; pub mod function;
pub use self::function::*; pub use self::function::*;
@ -10,6 +13,9 @@ pub use self::expression::*;
pub mod field; pub mod field;
pub mod integer;
pub use integer::*;
pub mod generate_constraints; pub mod generate_constraints;
pub use self::generate_constraints::*; pub use self::generate_constraints::*;

View File

@ -5,6 +5,7 @@ use crate::{
errors::{StatementError, ValueError}, errors::{StatementError, ValueError},
new_scope, new_scope,
GroupType, GroupType,
Integer,
}; };
use leo_types::{ use leo_types::{
Assignee, Assignee,
@ -13,7 +14,6 @@ use leo_types::{
Declare, Declare,
Expression, Expression,
Identifier, Identifier,
Integer,
RangeOrExpression, RangeOrExpression,
Span, Span,
Statement, Statement,

View File

@ -10,8 +10,9 @@ use crate::{
new_scope, new_scope,
FieldType, FieldType,
GroupType, GroupType,
Integer,
}; };
use leo_types::{Circuit, Function, Identifier, Integer, Span, Type}; use leo_types::{Circuit, Function, Identifier, Span, Type};
use crate::errors::ExpressionError; use crate::errors::ExpressionError;
use snarkos_errors::gadgets::SynthesisError; use snarkos_errors::gadgets::SynthesisError;

View File

@ -1,5 +1,5 @@
use crate::errors::{BooleanError, FieldError, FunctionError, GroupError, ValueError}; use crate::errors::{BooleanError, FieldError, FunctionError, GroupError, IntegerError, ValueError};
use leo_types::{Error as FormattedError, Identifier, IntegerError, Span}; use leo_types::{Error as FormattedError, Identifier, Span};
use snarkos_errors::gadgets::SynthesisError; use snarkos_errors::gadgets::SynthesisError;
use std::path::PathBuf; use std::path::PathBuf;

View File

@ -1,5 +1,5 @@
use crate::errors::{BooleanError, ExpressionError, FieldError, GroupError, StatementError, ValueError}; use crate::errors::{BooleanError, ExpressionError, FieldError, GroupError, IntegerError, StatementError, ValueError};
use leo_types::{Error as FormattedError, IntegerError, Span}; use leo_types::{Error as FormattedError, Span};
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Debug, Error)] #[derive(Debug, Error)]

View File

@ -1,4 +1,4 @@
use crate::{error::Error as FormattedError, Span}; use leo_types::{error::Error as FormattedError, Span};
use snarkos_errors::gadgets::SynthesisError; use snarkos_errors::gadgets::SynthesisError;
use std::path::PathBuf; use std::path::PathBuf;

View File

@ -12,6 +12,9 @@ pub use self::expression::*;
pub mod import; pub mod import;
pub use self::import::*; pub use self::import::*;
pub mod integer;
pub use integer::*;
pub mod field; pub mod field;
pub use self::field::*; pub use self::field::*;

View File

@ -1,5 +1,5 @@
use crate::errors::{BooleanError, ExpressionError, ValueError}; use crate::errors::{BooleanError, ExpressionError, IntegerError, ValueError};
use leo_types::{Error as FormattedError, IntegerError, Span, Type}; use leo_types::{Error as FormattedError, Span, Type};
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Debug, Error)] #[derive(Debug, Error)]

View File

@ -1,5 +1,5 @@
use crate::errors::{BooleanError, FieldError, GroupError}; use crate::errors::{BooleanError, FieldError, GroupError, IntegerError};
use leo_types::{Error as FormattedError, IntegerError, Span}; use leo_types::{Error as FormattedError, Span};
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Debug, Error)] #[derive(Debug, Error)]

View File

@ -3,6 +3,7 @@
use crate::errors::FieldError; use crate::errors::FieldError;
use leo_types::Span; use leo_types::Span;
use crate::{ComparatorGadget, EvaluateLtGadget};
use snarkos_errors::gadgets::SynthesisError; use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{ use snarkos_models::{
curves::{Field, PrimeField}, curves::{Field, PrimeField},
@ -210,6 +211,31 @@ impl<F: Field + PrimeField> EvaluateEqGadget<F> for FieldType<F> {
} }
} }
impl<F: Field + PrimeField> EvaluateLtGadget<F> for FieldType<F> {
fn less_than<CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
match (self, other) {
(FieldType::Constant(first), FieldType::Constant(second)) => Ok(Boolean::constant(first.lt(second))),
(FieldType::Allocated(allocated), FieldType::Constant(constant))
| (FieldType::Constant(constant), FieldType::Allocated(allocated)) => {
let bool_option = allocated.value.map(|f| f.lt(constant));
Boolean::alloc(&mut cs.ns(|| "less than"), || {
bool_option.ok_or(SynthesisError::AssignmentMissing)
})
}
(FieldType::Allocated(first), FieldType::Allocated(second)) => {
let bool_option = first.value.and_then(|a| second.value.map(|b| a.lt(&b)));
Boolean::alloc(&mut cs.ns(|| "less than"), || {
bool_option.ok_or(SynthesisError::AssignmentMissing)
})
}
}
}
}
impl<F: Field + PrimeField> ComparatorGadget<F> for FieldType<F> {}
impl<F: Field + PrimeField> EqGadget<F> for FieldType<F> {} impl<F: Field + PrimeField> EqGadget<F> for FieldType<F> {}
impl<F: Field + PrimeField> ConditionalEqGadget<F> for FieldType<F> { impl<F: Field + PrimeField> ConditionalEqGadget<F> for FieldType<F> {

View File

@ -9,9 +9,10 @@ use crate::{
use leo_compiler::{ use leo_compiler::{
errors::{CompilerError, FunctionError}, errors::{CompilerError, FunctionError},
ConstrainedValue, ConstrainedValue,
Integer,
}; };
use leo_inputs::types::{IntegerType, U32Type}; use leo_inputs::types::{IntegerType, U32Type};
use leo_types::{InputValue, Integer}; use leo_types::InputValue;
use snarkos_models::gadgets::utilities::uint::UInt32; use snarkos_models::gadgets::utilities::uint::UInt32;

View File

@ -10,8 +10,9 @@ use leo_compiler::{
errors::{CompilerError, ExpressionError, FunctionError, StatementError}, errors::{CompilerError, ExpressionError, FunctionError, StatementError},
ConstrainedCircuitMember, ConstrainedCircuitMember,
ConstrainedValue, ConstrainedValue,
Integer,
}; };
use leo_types::{Expression, Function, Identifier, Integer, Span, Statement, Type}; use leo_types::{Expression, Function, Identifier, Span, Statement, Type};
use snarkos_models::gadgets::utilities::uint::UInt32; use snarkos_models::gadgets::utilities::uint::UInt32;

View File

@ -2,8 +2,7 @@
pub mod macros; pub mod macros;
use crate::{get_error, EdwardsTestCompiler}; use crate::{get_error, EdwardsTestCompiler};
use leo_compiler::errors::{CompilerError, FunctionError}; use leo_compiler::errors::{CompilerError, FunctionError, IntegerError};
use leo_types::IntegerError;
pub trait IntegerTester { pub trait IntegerTester {
/// Tests use of the integer in a function input /// Tests use of the integer in a function input

View File

@ -7,9 +7,9 @@ use crate::{
EdwardsConstrainedValue, EdwardsConstrainedValue,
EdwardsTestCompiler, EdwardsTestCompiler,
}; };
use leo_compiler::ConstrainedValue; use leo_compiler::{ConstrainedValue, Integer};
use leo_inputs::types::{IntegerType, U128Type}; use leo_inputs::types::{IntegerType, U128Type};
use leo_types::{InputValue, Integer}; use leo_types::InputValue;
use snarkos_curves::edwards_bls12::Fq; use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::{ use snarkos_models::gadgets::{

View File

@ -7,9 +7,9 @@ use crate::{
EdwardsConstrainedValue, EdwardsConstrainedValue,
EdwardsTestCompiler, EdwardsTestCompiler,
}; };
use leo_compiler::ConstrainedValue; use leo_compiler::{ConstrainedValue, Integer};
use leo_inputs::types::{IntegerType, U16Type}; use leo_inputs::types::{IntegerType, U16Type};
use leo_types::{InputValue, Integer}; use leo_types::InputValue;
use snarkos_curves::edwards_bls12::Fq; use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::{ use snarkos_models::gadgets::{

View File

@ -7,9 +7,9 @@ use crate::{
EdwardsConstrainedValue, EdwardsConstrainedValue,
EdwardsTestCompiler, EdwardsTestCompiler,
}; };
use leo_compiler::ConstrainedValue; use leo_compiler::{ConstrainedValue, Integer};
use leo_inputs::types::{IntegerType, U32Type}; use leo_inputs::types::{IntegerType, U32Type};
use leo_types::{InputValue, Integer}; use leo_types::InputValue;
use snarkos_curves::edwards_bls12::Fq; use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::{ use snarkos_models::gadgets::{

View File

@ -7,9 +7,9 @@ use crate::{
EdwardsConstrainedValue, EdwardsConstrainedValue,
EdwardsTestCompiler, EdwardsTestCompiler,
}; };
use leo_compiler::ConstrainedValue; use leo_compiler::{ConstrainedValue, Integer};
use leo_inputs::types::{IntegerType, U64Type}; use leo_inputs::types::{IntegerType, U64Type};
use leo_types::{InputValue, Integer}; use leo_types::InputValue;
use snarkos_curves::edwards_bls12::Fq; use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::{ use snarkos_models::gadgets::{

View File

@ -7,9 +7,9 @@ use crate::{
EdwardsConstrainedValue, EdwardsConstrainedValue,
EdwardsTestCompiler, EdwardsTestCompiler,
}; };
use leo_compiler::ConstrainedValue; use leo_compiler::{ConstrainedValue, Integer};
use leo_inputs::types::{IntegerType, U8Type}; use leo_inputs::types::{IntegerType, U8Type};
use leo_types::{InputValue, Integer}; use leo_types::InputValue;
use snarkos_curves::edwards_bls12::Fq; use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::{ use snarkos_models::gadgets::{

View File

@ -2,8 +2,8 @@ use crate::{array::input_value_u32_one, parse_program, EdwardsConstrainedValue,
use leo_compiler::{ use leo_compiler::{
errors::{CompilerError, FunctionError, StatementError}, errors::{CompilerError, FunctionError, StatementError},
ConstrainedValue, ConstrainedValue,
Integer,
}; };
use leo_types::Integer;
use snarkos_curves::edwards_bls12::Fq; use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::{r1cs::TestConstraintSystem, utilities::uint::UInt32}; use snarkos_models::gadgets::{r1cs::TestConstraintSystem, utilities::uint::UInt32};

View File

@ -13,4 +13,3 @@ snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a5
pest = { version = "2.0" } pest = { version = "2.0" }
serde = { version = "1.0" } serde = { version = "1.0" }
thiserror = { version = "1.0" }

View File

@ -1,5 +1,2 @@
pub mod error; pub mod error;
pub use error::*; pub use error::*;
pub mod integer;
pub use integer::*;

View File

@ -1,6 +1,3 @@
#[macro_use]
extern crate thiserror;
pub mod circuits; pub mod circuits;
pub use self::circuits::*; pub use self::circuits::*;
@ -22,9 +19,6 @@ pub use self::imports::*;
pub mod inputs; pub mod inputs;
pub use self::inputs::*; pub use self::inputs::*;
pub mod integer;
pub use self::integer::*;
pub mod program; pub mod program;
pub use self::program::*; pub use self::program::*;