mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-26 03:33:44 +03:00
Merge pull request #73 from AleoHQ/feature/comparator
Feature/comparator
This commit is contained in:
commit
14adaaa820
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -607,7 +607,6 @@ dependencies = [
|
||||
"serde",
|
||||
"snarkos-errors",
|
||||
"snarkos-models",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
28
compiler/src/constraints/comparator.rs
Normal file
28
compiler/src/constraints/comparator.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
//! Methods to enforce constraints on expressions in a resolved Leo program.
|
||||
|
||||
use crate::{
|
||||
comparator::{ComparatorGadget, EvaluateLtGadget},
|
||||
constraints::{
|
||||
boolean::{enforce_and, enforce_or, evaluate_not, new_bool_constant},
|
||||
new_scope,
|
||||
@ -11,13 +12,13 @@ use crate::{
|
||||
errors::ExpressionError,
|
||||
FieldType,
|
||||
GroupType,
|
||||
Integer,
|
||||
};
|
||||
use leo_types::{
|
||||
CircuitFieldDefinition,
|
||||
CircuitMember,
|
||||
Expression,
|
||||
Identifier,
|
||||
Integer,
|
||||
IntegerType,
|
||||
RangeOrExpression,
|
||||
Span,
|
||||
@ -76,11 +77,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||
Ok(ConstrainedValue::Integer(num_1.add(cs, num_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||
Ok(ConstrainedValue::Field(fe_1.add(cs, &fe_2, span)?))
|
||||
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
|
||||
Ok(ConstrainedValue::Field(field_1.add(cs, &field_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
|
||||
Ok(ConstrainedValue::Group(ge_1.add(cs, &ge_2, span)?))
|
||||
(ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => {
|
||||
Ok(ConstrainedValue::Group(point_1.add(cs, &point_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
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)) => {
|
||||
Ok(ConstrainedValue::Integer(num_1.sub(cs, num_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||
Ok(ConstrainedValue::Field(fe_1.sub(cs, &fe_2, span)?))
|
||||
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
|
||||
Ok(ConstrainedValue::Field(field_1.sub(cs, &field_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
|
||||
Ok(ConstrainedValue::Group(ge_1.sub(cs, &ge_2, span)?))
|
||||
(ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => {
|
||||
Ok(ConstrainedValue::Group(point_1.sub(cs, &point_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
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)) => {
|
||||
Ok(ConstrainedValue::Integer(num_1.mul(cs, num_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||
Ok(ConstrainedValue::Field(fe_1.mul(cs, &fe_2, span)?))
|
||||
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
|
||||
Ok(ConstrainedValue::Field(field_1.mul(cs, &field_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
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)) => {
|
||||
Ok(ConstrainedValue::Integer(num_1.div(cs, num_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||
Ok(ConstrainedValue::Field(fe_1.div(cs, &fe_2, span)?))
|
||||
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
|
||||
Ok(ConstrainedValue::Field(field_1.div(cs, &field_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
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)) => {
|
||||
num_1.evaluate_equal(unique_namespace, &num_2)
|
||||
}
|
||||
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||
fe_1.evaluate_equal(unique_namespace, &fe_2)
|
||||
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
|
||||
field_1.evaluate_equal(unique_namespace, &field_2)
|
||||
}
|
||||
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
|
||||
ge_1.evaluate_equal(unique_namespace, &ge_2)
|
||||
(ConstrainedValue::Group(point_1), ConstrainedValue::Group(point_2)) => {
|
||||
point_1.evaluate_equal(unique_namespace, &point_2)
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
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 =
|
||||
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))
|
||||
}
|
||||
|
||||
//TODO: unsafe for allocated values
|
||||
fn evaluate_ge_expression(
|
||||
fn evaluate_ge_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
) -> 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)) => {
|
||||
let result = num_1.ge(&num_2);
|
||||
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
|
||||
num_1.greater_than_or_equal(unique_namespace, &num_2)
|
||||
}
|
||||
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||
let result = fe_1.ge(&fe_2);
|
||||
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
|
||||
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
|
||||
field_1.greater_than_or_equal(unique_namespace, &field_2)
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
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)) => {
|
||||
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(
|
||||
format!("{} >= {}", val_1, val_2),
|
||||
span,
|
||||
)),
|
||||
}
|
||||
(val_1, val_2) => {
|
||||
return Err(ExpressionError::incompatible_types(
|
||||
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(
|
||||
fn evaluate_gt_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
) -> 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)) => {
|
||||
let result = num_1.gt(&num_2);
|
||||
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
|
||||
num_1.greater_than(unique_namespace, &num_2)
|
||||
}
|
||||
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||
let result = fe_1.gt(&fe_2);
|
||||
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
|
||||
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
|
||||
field_1.greater_than(unique_namespace, &field_2)
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
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)) => {
|
||||
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(
|
||||
format!("{} > {}", val_1, val_2),
|
||||
span,
|
||||
)),
|
||||
}
|
||||
(val_1, val_2) => {
|
||||
return Err(ExpressionError::incompatible_types(
|
||||
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(
|
||||
fn evaluate_le_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
) -> 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)) => {
|
||||
let result = num_1.le(&num_2);
|
||||
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
|
||||
num_1.less_than_or_equal(unique_namespace, &num_2)
|
||||
}
|
||||
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||
let result = fe_1.le(&fe_2);
|
||||
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
|
||||
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
|
||||
field_1.less_than_or_equal(unique_namespace, &field_2)
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
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)) => {
|
||||
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(
|
||||
format!("{} <= {}", val_1, val_2),
|
||||
span,
|
||||
)),
|
||||
}
|
||||
(val_1, val_2) => {
|
||||
return Err(ExpressionError::incompatible_types(
|
||||
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(
|
||||
fn evaluate_lt_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
) -> 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)) => {
|
||||
let result = num_1.lt(&num_2);
|
||||
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
|
||||
num_1.less_than(unique_namespace, &num_2)
|
||||
}
|
||||
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||
let result = fe_1.lt(&fe_2);
|
||||
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
|
||||
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
|
||||
field_1.less_than(unique_namespace, &field_2)
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
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)) => {
|
||||
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(
|
||||
format!("{} < {}", val_1, val_2,),
|
||||
span,
|
||||
)),
|
||||
}
|
||||
(val_1, val_2) => {
|
||||
return Err(ExpressionError::incompatible_types(
|
||||
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
|
||||
@ -1029,7 +1054,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
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) => {
|
||||
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(),
|
||||
)?;
|
||||
|
||||
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) => {
|
||||
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(),
|
||||
)?;
|
||||
|
||||
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) => {
|
||||
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(),
|
||||
)?;
|
||||
|
||||
Ok(self.evaluate_lt_expression(resolved_left, resolved_right, span)?)
|
||||
Ok(self.evaluate_lt_expression(cs, resolved_left, resolved_right, span)?)
|
||||
}
|
||||
|
||||
// Conditionals
|
||||
|
@ -12,8 +12,10 @@ use crate::{
|
||||
},
|
||||
errors::{FunctionError, StatementError},
|
||||
GroupType,
|
||||
Integer,
|
||||
};
|
||||
use leo_types::{Expression, Function, InputValue, Integer, Span, Type};
|
||||
|
||||
use leo_types::{Expression, Function, InputValue, Span, Type};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Conversion of integer declarations to constraints in Leo.
|
||||
|
||||
use crate::{errors::IntegerError, InputValue, IntegerType, Span};
|
||||
use crate::{errors::IntegerError, ComparatorGadget, EvaluateLtGadget};
|
||||
use leo_types::{InputValue, IntegerType, Span};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use snarkos_models::{
|
||||
@ -88,6 +88,16 @@ impl Integer {
|
||||
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 {
|
||||
match self {
|
||||
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> ConditionalEqGadget<F> for Integer {
|
@ -2,6 +2,9 @@
|
||||
|
||||
pub mod boolean;
|
||||
|
||||
pub(crate) mod comparator;
|
||||
pub(crate) use comparator::*;
|
||||
|
||||
pub mod function;
|
||||
pub use self::function::*;
|
||||
|
||||
@ -10,6 +13,9 @@ pub use self::expression::*;
|
||||
|
||||
pub mod field;
|
||||
|
||||
pub mod integer;
|
||||
pub use integer::*;
|
||||
|
||||
pub mod generate_constraints;
|
||||
pub use self::generate_constraints::*;
|
||||
|
||||
|
@ -5,6 +5,7 @@ use crate::{
|
||||
errors::{StatementError, ValueError},
|
||||
new_scope,
|
||||
GroupType,
|
||||
Integer,
|
||||
};
|
||||
use leo_types::{
|
||||
Assignee,
|
||||
@ -13,7 +14,6 @@ use leo_types::{
|
||||
Declare,
|
||||
Expression,
|
||||
Identifier,
|
||||
Integer,
|
||||
RangeOrExpression,
|
||||
Span,
|
||||
Statement,
|
||||
|
@ -10,8 +10,9 @@ use crate::{
|
||||
new_scope,
|
||||
FieldType,
|
||||
GroupType,
|
||||
Integer,
|
||||
};
|
||||
use leo_types::{Circuit, Function, Identifier, Integer, Span, Type};
|
||||
use leo_types::{Circuit, Function, Identifier, Span, Type};
|
||||
|
||||
use crate::errors::ExpressionError;
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::errors::{BooleanError, FieldError, FunctionError, GroupError, ValueError};
|
||||
use leo_types::{Error as FormattedError, Identifier, IntegerError, Span};
|
||||
use crate::errors::{BooleanError, FieldError, FunctionError, GroupError, IntegerError, ValueError};
|
||||
use leo_types::{Error as FormattedError, Identifier, Span};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use std::path::PathBuf;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::errors::{BooleanError, ExpressionError, FieldError, GroupError, StatementError, ValueError};
|
||||
use leo_types::{Error as FormattedError, IntegerError, Span};
|
||||
use crate::errors::{BooleanError, ExpressionError, FieldError, GroupError, IntegerError, StatementError, ValueError};
|
||||
use leo_types::{Error as FormattedError, Span};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
@ -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 std::path::PathBuf;
|
@ -12,6 +12,9 @@ pub use self::expression::*;
|
||||
pub mod import;
|
||||
pub use self::import::*;
|
||||
|
||||
pub mod integer;
|
||||
pub use integer::*;
|
||||
|
||||
pub mod field;
|
||||
pub use self::field::*;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::errors::{BooleanError, ExpressionError, ValueError};
|
||||
use leo_types::{Error as FormattedError, IntegerError, Span, Type};
|
||||
use crate::errors::{BooleanError, ExpressionError, IntegerError, ValueError};
|
||||
use leo_types::{Error as FormattedError, Span, Type};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::errors::{BooleanError, FieldError, GroupError};
|
||||
use leo_types::{Error as FormattedError, IntegerError, Span};
|
||||
use crate::errors::{BooleanError, FieldError, GroupError, IntegerError};
|
||||
use leo_types::{Error as FormattedError, Span};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
@ -3,6 +3,7 @@
|
||||
use crate::errors::FieldError;
|
||||
use leo_types::Span;
|
||||
|
||||
use crate::{ComparatorGadget, EvaluateLtGadget};
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use snarkos_models::{
|
||||
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> ConditionalEqGadget<F> for FieldType<F> {
|
||||
|
@ -9,9 +9,10 @@ use crate::{
|
||||
use leo_compiler::{
|
||||
errors::{CompilerError, FunctionError},
|
||||
ConstrainedValue,
|
||||
Integer,
|
||||
};
|
||||
use leo_inputs::types::{IntegerType, U32Type};
|
||||
use leo_types::{InputValue, Integer};
|
||||
use leo_types::InputValue;
|
||||
|
||||
use snarkos_models::gadgets::utilities::uint::UInt32;
|
||||
|
||||
|
@ -10,8 +10,9 @@ use leo_compiler::{
|
||||
errors::{CompilerError, ExpressionError, FunctionError, StatementError},
|
||||
ConstrainedCircuitMember,
|
||||
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;
|
||||
|
||||
|
@ -2,8 +2,7 @@
|
||||
pub mod macros;
|
||||
|
||||
use crate::{get_error, EdwardsTestCompiler};
|
||||
use leo_compiler::errors::{CompilerError, FunctionError};
|
||||
use leo_types::IntegerError;
|
||||
use leo_compiler::errors::{CompilerError, FunctionError, IntegerError};
|
||||
|
||||
pub trait IntegerTester {
|
||||
/// Tests use of the integer in a function input
|
||||
|
@ -7,9 +7,9 @@ use crate::{
|
||||
EdwardsConstrainedValue,
|
||||
EdwardsTestCompiler,
|
||||
};
|
||||
use leo_compiler::ConstrainedValue;
|
||||
use leo_compiler::{ConstrainedValue, Integer};
|
||||
use leo_inputs::types::{IntegerType, U128Type};
|
||||
use leo_types::{InputValue, Integer};
|
||||
use leo_types::InputValue;
|
||||
|
||||
use snarkos_curves::edwards_bls12::Fq;
|
||||
use snarkos_models::gadgets::{
|
||||
|
@ -7,9 +7,9 @@ use crate::{
|
||||
EdwardsConstrainedValue,
|
||||
EdwardsTestCompiler,
|
||||
};
|
||||
use leo_compiler::ConstrainedValue;
|
||||
use leo_compiler::{ConstrainedValue, Integer};
|
||||
use leo_inputs::types::{IntegerType, U16Type};
|
||||
use leo_types::{InputValue, Integer};
|
||||
use leo_types::InputValue;
|
||||
|
||||
use snarkos_curves::edwards_bls12::Fq;
|
||||
use snarkos_models::gadgets::{
|
||||
|
@ -7,9 +7,9 @@ use crate::{
|
||||
EdwardsConstrainedValue,
|
||||
EdwardsTestCompiler,
|
||||
};
|
||||
use leo_compiler::ConstrainedValue;
|
||||
use leo_compiler::{ConstrainedValue, Integer};
|
||||
use leo_inputs::types::{IntegerType, U32Type};
|
||||
use leo_types::{InputValue, Integer};
|
||||
use leo_types::InputValue;
|
||||
|
||||
use snarkos_curves::edwards_bls12::Fq;
|
||||
use snarkos_models::gadgets::{
|
||||
|
@ -7,9 +7,9 @@ use crate::{
|
||||
EdwardsConstrainedValue,
|
||||
EdwardsTestCompiler,
|
||||
};
|
||||
use leo_compiler::ConstrainedValue;
|
||||
use leo_compiler::{ConstrainedValue, Integer};
|
||||
use leo_inputs::types::{IntegerType, U64Type};
|
||||
use leo_types::{InputValue, Integer};
|
||||
use leo_types::InputValue;
|
||||
|
||||
use snarkos_curves::edwards_bls12::Fq;
|
||||
use snarkos_models::gadgets::{
|
||||
|
@ -7,9 +7,9 @@ use crate::{
|
||||
EdwardsConstrainedValue,
|
||||
EdwardsTestCompiler,
|
||||
};
|
||||
use leo_compiler::ConstrainedValue;
|
||||
use leo_compiler::{ConstrainedValue, Integer};
|
||||
use leo_inputs::types::{IntegerType, U8Type};
|
||||
use leo_types::{InputValue, Integer};
|
||||
use leo_types::InputValue;
|
||||
|
||||
use snarkos_curves::edwards_bls12::Fq;
|
||||
use snarkos_models::gadgets::{
|
||||
|
@ -2,8 +2,8 @@ use crate::{array::input_value_u32_one, parse_program, EdwardsConstrainedValue,
|
||||
use leo_compiler::{
|
||||
errors::{CompilerError, FunctionError, StatementError},
|
||||
ConstrainedValue,
|
||||
Integer,
|
||||
};
|
||||
use leo_types::Integer;
|
||||
|
||||
use snarkos_curves::edwards_bls12::Fq;
|
||||
use snarkos_models::gadgets::{r1cs::TestConstraintSystem, utilities::uint::UInt32};
|
||||
|
@ -13,4 +13,3 @@ snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a5
|
||||
|
||||
pest = { version = "2.0" }
|
||||
serde = { version = "1.0" }
|
||||
thiserror = { version = "1.0" }
|
||||
|
@ -1,5 +1,2 @@
|
||||
pub mod error;
|
||||
pub use error::*;
|
||||
|
||||
pub mod integer;
|
||||
pub use integer::*;
|
||||
|
@ -1,6 +1,3 @@
|
||||
#[macro_use]
|
||||
extern crate thiserror;
|
||||
|
||||
pub mod circuits;
|
||||
pub use self::circuits::*;
|
||||
|
||||
@ -22,9 +19,6 @@ pub use self::imports::*;
|
||||
pub mod inputs;
|
||||
pub use self::inputs::*;
|
||||
|
||||
pub mod integer;
|
||||
pub use self::integer::*;
|
||||
|
||||
pub mod program;
|
||||
pub use self::program::*;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user