mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-25 11:12:48 +03:00
Merge pull request #39 from AleoHQ/refactor/field-type
Refactor/field type
This commit is contained in:
commit
110bca2463
108
README.md
108
README.md
@ -60,19 +60,20 @@ function main() -> field {
|
|||||||
let c = b - 1;
|
let c = b - 1;
|
||||||
let d = c * 4;
|
let d = c * 4;
|
||||||
let e = d / 2;
|
let e = d / 2;
|
||||||
let f = e ** 3u32; //Field exponents must be a `u32` type.
|
return e
|
||||||
return f
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Group Elements
|
### Affine Points
|
||||||
|
The set of affine points on the elliptic curve passed into the leo compiler forms a group.
|
||||||
|
Leo supports this set as a primitive data type.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
function main() -> group {
|
function main() -> group {
|
||||||
let a = 1000group; // explicit type
|
let a = 1000group; // explicit type
|
||||||
let a: group = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // explicit type
|
let a = (21888242871839275222246405745257275088548364400416034343698204186575808495617, 21888242871839275222246405745257275088548364400416034343698204186575808495617)group; // explicit type
|
||||||
let b = a + 1; // implicit type
|
let b = a + 0; // implicit type
|
||||||
let c = b - 1;
|
let c = b - 0;
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -142,6 +143,8 @@ function main() -> u32 {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### If Else Conditional Statement
|
### If Else Conditional Statement
|
||||||
|
** **Experimental** **
|
||||||
|
The current constraint system is not optimized for statement branching. Please use the ternary expression above until this feature is stable.
|
||||||
```rust
|
```rust
|
||||||
function main(a: private bool, b: private bool) -> u32 {
|
function main(a: private bool, b: private bool) -> u32 {
|
||||||
let mut res = 0u32;
|
let mut res = 0u32;
|
||||||
@ -158,7 +161,7 @@ function main(a: private bool, b: private bool) -> u32 {
|
|||||||
|
|
||||||
### For loop
|
### For loop
|
||||||
```rust
|
```rust
|
||||||
function main() -> field {
|
function main() -> fe {
|
||||||
let mut a = 1field;
|
let mut a = 1field;
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
a = a + 1;
|
a = a + 1;
|
||||||
@ -173,7 +176,7 @@ function test1(a : u32) -> u32 {
|
|||||||
return a + 1
|
return a + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
function test2(b: field) -> field {
|
function test2(b: fe) -> field {
|
||||||
return b * 2field
|
return b * 2field
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +229,12 @@ function main(a: public field) -> field {
|
|||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
Private by default. Below `a` is implicitly private.
|
||||||
|
```rust
|
||||||
|
function main(a: field) -> field {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
```
|
||||||
Function inputs are passed by value.
|
Function inputs are passed by value.
|
||||||
```rust
|
```rust
|
||||||
function test(mut a: u32) {
|
function test(mut a: u32) {
|
||||||
@ -241,28 +250,61 @@ function main() -> u32 {
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Circuits
|
## Circuits
|
||||||
```rust
|
Circuits in Leo are similar to classes in object oriented langauges. Circuits are defined above functions in a Leo program. Circuits can have one or more members.
|
||||||
bab
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
Members can be defined as fields which hold primitive values
|
||||||
```rust
|
```rust
|
||||||
circuit Point {
|
circuit Point {
|
||||||
x: u32
|
x: u32
|
||||||
y: u32
|
y: u32
|
||||||
}
|
}
|
||||||
function main() -> u32 {
|
function main() -> u32 {
|
||||||
let p = Point {x: 1, y: 0}
|
let p = Point {x: 1, y: 0};
|
||||||
return p.x
|
return p.x
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Members can also be defined as functions.
|
||||||
```rust
|
```rust
|
||||||
circuit Foo {
|
circuit Circ {
|
||||||
x: bool
|
function echo(x: u32) -> u32 {
|
||||||
|
return x
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function main() -> Foo {
|
|
||||||
let mut f = Foo {x: true};
|
function main() -> u32 {
|
||||||
f.x = false;
|
let c = Circ { };
|
||||||
return f
|
return c.echo(1u32)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Circuit functions can be made static, enabling them to be called without instantiation.
|
||||||
|
```rust
|
||||||
|
circuit Circ {
|
||||||
|
static function echo(x: u32) -> u32 {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() -> u32 {
|
||||||
|
return Circ::echo(1u32)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Self` keyword is supported in circuit functions.
|
||||||
|
```rust
|
||||||
|
circuit Circ {
|
||||||
|
b: bool
|
||||||
|
|
||||||
|
static function new() -> Self {
|
||||||
|
return Self { b: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() -> Circ {
|
||||||
|
let c = Circ::new();
|
||||||
|
return c.b
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -311,12 +353,34 @@ This will enforce that the two values are equal in the constraint system.
|
|||||||
function main() {
|
function main() {
|
||||||
assert_eq(45, 45);
|
assert_eq(45, 45);
|
||||||
|
|
||||||
assert_eq(2field, 2field);
|
assert_eq(2fe, 2fe);
|
||||||
|
|
||||||
assert_eq(true, true);
|
assert_eq(true, true);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Use the `test` keyword to add tests to a leo program. Tests must have 0 function inputs and 0 function returns.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
function main(a: u32) -> u32 {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
test function expect_pass() {
|
||||||
|
let a = 1u32;
|
||||||
|
|
||||||
|
let res = main(a);
|
||||||
|
|
||||||
|
assert_eq!(res, 1u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
test function expect_fail() {
|
||||||
|
assert_eq!(1u8, 0u8);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
# Leo CLI
|
# Leo CLI
|
||||||
|
|
||||||
@ -361,6 +425,12 @@ To execute unit tests on your program, run:
|
|||||||
```
|
```
|
||||||
leo test
|
leo test
|
||||||
```
|
```
|
||||||
|
The results of test compilation and the constraint system will be printed:
|
||||||
|
```
|
||||||
|
INFO leo Running 2 tests
|
||||||
|
INFO leo test language::expect_pass compiled. Constraint system satisfied: true
|
||||||
|
ERROR leo test language::expect_fail errored: Assertion 1u8 == 0u8 failed
|
||||||
|
```
|
||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
|
||||||
|
@ -90,10 +90,10 @@ pub enum BinaryOperator {
|
|||||||
Or,
|
Or,
|
||||||
And,
|
And,
|
||||||
Eq,
|
Eq,
|
||||||
Neq,
|
Ne,
|
||||||
Geq,
|
Ge,
|
||||||
Gt,
|
Gt,
|
||||||
Leq,
|
Le,
|
||||||
Lt,
|
Lt,
|
||||||
Add,
|
Add,
|
||||||
Sub,
|
Sub,
|
||||||
@ -812,10 +812,10 @@ fn precedence_climber() -> PrecClimber<Rule> {
|
|||||||
Operator::new(Rule::operation_or, Assoc::Left),
|
Operator::new(Rule::operation_or, Assoc::Left),
|
||||||
Operator::new(Rule::operation_and, Assoc::Left),
|
Operator::new(Rule::operation_and, Assoc::Left),
|
||||||
Operator::new(Rule::operation_eq, Assoc::Left)
|
Operator::new(Rule::operation_eq, Assoc::Left)
|
||||||
| Operator::new(Rule::operation_neq, Assoc::Left),
|
| Operator::new(Rule::operation_ne, Assoc::Left),
|
||||||
Operator::new(Rule::operation_geq, Assoc::Left)
|
Operator::new(Rule::operation_ge, Assoc::Left)
|
||||||
| Operator::new(Rule::operation_gt, Assoc::Left)
|
| Operator::new(Rule::operation_gt, Assoc::Left)
|
||||||
| Operator::new(Rule::operation_leq, Assoc::Left)
|
| Operator::new(Rule::operation_le, Assoc::Left)
|
||||||
| Operator::new(Rule::operation_lt, Assoc::Left),
|
| Operator::new(Rule::operation_lt, Assoc::Left),
|
||||||
Operator::new(Rule::operation_add, Assoc::Left)
|
Operator::new(Rule::operation_add, Assoc::Left)
|
||||||
| Operator::new(Rule::operation_sub, Assoc::Left),
|
| Operator::new(Rule::operation_sub, Assoc::Left),
|
||||||
@ -927,10 +927,10 @@ fn binary_expression<'ast>(
|
|||||||
Rule::operation_or => Expression::binary(BinaryOperator::Or, lhs, rhs, span),
|
Rule::operation_or => Expression::binary(BinaryOperator::Or, lhs, rhs, span),
|
||||||
Rule::operation_and => Expression::binary(BinaryOperator::And, lhs, rhs, span),
|
Rule::operation_and => Expression::binary(BinaryOperator::And, lhs, rhs, span),
|
||||||
Rule::operation_eq => Expression::binary(BinaryOperator::Eq, lhs, rhs, span),
|
Rule::operation_eq => Expression::binary(BinaryOperator::Eq, lhs, rhs, span),
|
||||||
Rule::operation_neq => Expression::binary(BinaryOperator::Neq, lhs, rhs, span),
|
Rule::operation_ne => Expression::binary(BinaryOperator::Ne, lhs, rhs, span),
|
||||||
Rule::operation_geq => Expression::binary(BinaryOperator::Geq, lhs, rhs, span),
|
Rule::operation_ge => Expression::binary(BinaryOperator::Ge, lhs, rhs, span),
|
||||||
Rule::operation_gt => Expression::binary(BinaryOperator::Gt, lhs, rhs, span),
|
Rule::operation_gt => Expression::binary(BinaryOperator::Gt, lhs, rhs, span),
|
||||||
Rule::operation_leq => Expression::binary(BinaryOperator::Leq, lhs, rhs, span),
|
Rule::operation_le => Expression::binary(BinaryOperator::Le, lhs, rhs, span),
|
||||||
Rule::operation_lt => Expression::binary(BinaryOperator::Lt, lhs, rhs, span),
|
Rule::operation_lt => Expression::binary(BinaryOperator::Lt, lhs, rhs, span),
|
||||||
Rule::operation_add => Expression::binary(BinaryOperator::Add, lhs, rhs, span),
|
Rule::operation_add => Expression::binary(BinaryOperator::Add, lhs, rhs, span),
|
||||||
Rule::operation_sub => Expression::binary(BinaryOperator::Sub, lhs, rhs, span),
|
Rule::operation_sub => Expression::binary(BinaryOperator::Sub, lhs, rhs, span),
|
||||||
|
@ -21,8 +21,8 @@ use std::{fs, marker::PhantomData, path::PathBuf};
|
|||||||
pub struct Compiler<F: Field + PrimeField, G: GroupType<F>> {
|
pub struct Compiler<F: Field + PrimeField, G: GroupType<F>> {
|
||||||
package_name: String,
|
package_name: String,
|
||||||
main_file_path: PathBuf,
|
main_file_path: PathBuf,
|
||||||
program: Program<F>,
|
program: Program,
|
||||||
program_inputs: Vec<Option<InputValue<F>>>,
|
program_inputs: Vec<Option<InputValue>>,
|
||||||
output: Option<ConstrainedValue<F, G>>,
|
output: Option<ConstrainedValue<F, G>>,
|
||||||
_engine: PhantomData<F>,
|
_engine: PhantomData<F>,
|
||||||
}
|
}
|
||||||
@ -44,7 +44,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
Ok(program)
|
Ok(program)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_inputs(&mut self, program_inputs: Vec<Option<InputValue<F>>>) {
|
pub fn set_inputs(&mut self, program_inputs: Vec<Option<InputValue>>) {
|
||||||
self.program_inputs = program_inputs;
|
self.program_inputs = program_inputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
// Build program from abstract syntax tree
|
// Build program from abstract syntax tree
|
||||||
let package_name = self.package_name.clone();
|
let package_name = self.package_name.clone();
|
||||||
|
|
||||||
self.program = Program::<F>::from(syntax_tree, package_name);
|
self.program = Program::from(syntax_tree, package_name);
|
||||||
self.program_inputs = vec![None; self.program.num_parameters];
|
self.program_inputs = vec![None; self.program.num_parameters];
|
||||||
|
|
||||||
log::debug!("Program parsing complete\n{:#?}", self.program);
|
log::debug!("Program parsing complete\n{:#?}", self.program);
|
||||||
|
@ -22,7 +22,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
name: String,
|
name: String,
|
||||||
private: bool,
|
private: bool,
|
||||||
input_value: Option<InputValue<F>>,
|
input_value: Option<InputValue>,
|
||||||
) -> Result<ConstrainedValue<F, G>, BooleanError> {
|
) -> Result<ConstrainedValue<F, G>, BooleanError> {
|
||||||
// Check that the input value is the correct type
|
// Check that the input value is the correct type
|
||||||
let bool_value = match input_value {
|
let bool_value = match input_value {
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
CircuitFieldDefinition, CircuitMember, Expression, Identifier, RangeOrExpression,
|
CircuitFieldDefinition, CircuitMember, Expression, Identifier, RangeOrExpression,
|
||||||
SpreadOrExpression,
|
SpreadOrExpression,
|
||||||
},
|
},
|
||||||
GroupType, Integer, IntegerType, Type,
|
FieldType, GroupType, Integer, IntegerType, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
use snarkos_models::{
|
use snarkos_models::{
|
||||||
@ -25,8 +25,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
&mut self,
|
&mut self,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
expected_types: &Vec<Type<F>>,
|
expected_types: &Vec<Type>,
|
||||||
unresolved_identifier: Identifier<F>,
|
unresolved_identifier: Identifier,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
// Evaluate the identifier name in the current function scope
|
// Evaluate the identifier name in the current function scope
|
||||||
let variable_name = new_scope(function_scope, unresolved_identifier.to_string());
|
let variable_name = new_scope(function_scope, unresolved_identifier.to_string());
|
||||||
@ -60,8 +60,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||||
Ok(Self::enforce_integer_add(cs, num_1, num_2)?)
|
Ok(Self::enforce_integer_add(cs, num_1, num_2)?)
|
||||||
}
|
}
|
||||||
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
|
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||||
Ok(self.enforce_field_add(cs, fe_1, fe_2)?)
|
Ok(ConstrainedValue::Field(fe_1.add(cs, &fe_2)?))
|
||||||
}
|
}
|
||||||
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
|
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
|
||||||
Ok(ConstrainedValue::Group(ge_1.add(cs, &ge_2)?))
|
Ok(ConstrainedValue::Group(ge_1.add(cs, &ge_2)?))
|
||||||
@ -91,8 +91,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||||
Ok(Self::enforce_integer_sub(cs, num_1, num_2)?)
|
Ok(Self::enforce_integer_sub(cs, num_1, num_2)?)
|
||||||
}
|
}
|
||||||
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
|
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||||
Ok(self.enforce_field_sub(cs, fe_1, fe_2)?)
|
Ok(ConstrainedValue::Field(fe_1.sub(cs, &fe_2)?))
|
||||||
}
|
}
|
||||||
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
|
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
|
||||||
Ok(ConstrainedValue::Group(ge_1.sub(cs, &ge_2)?))
|
Ok(ConstrainedValue::Group(ge_1.sub(cs, &ge_2)?))
|
||||||
@ -122,8 +122,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||||
Ok(Self::enforce_integer_mul(cs, num_1, num_2)?)
|
Ok(Self::enforce_integer_mul(cs, num_1, num_2)?)
|
||||||
}
|
}
|
||||||
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
|
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||||
Ok(self.enforce_field_mul(cs, fe_1, fe_2)?)
|
Ok(ConstrainedValue::Field(fe_1.mul(cs, &fe_2)?))
|
||||||
}
|
}
|
||||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||||
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
|
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
|
||||||
@ -152,8 +152,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||||
Ok(Self::enforce_integer_div(cs, num_1, num_2)?)
|
Ok(Self::enforce_integer_div(cs, num_1, num_2)?)
|
||||||
}
|
}
|
||||||
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
|
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||||
Ok(self.enforce_field_div(cs, fe_1, fe_2)?)
|
Ok(ConstrainedValue::Field(fe_1.div(cs, &fe_2)?))
|
||||||
}
|
}
|
||||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||||
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
|
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
|
||||||
@ -181,9 +181,6 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||||
Ok(Self::enforce_integer_pow(cs, num_1, num_2)?)
|
Ok(Self::enforce_integer_pow(cs, num_1, num_2)?)
|
||||||
}
|
}
|
||||||
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::Integer(num_2)) => {
|
|
||||||
Ok(self.enforce_field_pow(cs, fe_1, num_2)?)
|
|
||||||
}
|
|
||||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||||
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
|
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
|
||||||
self.enforce_pow_expression(cs, val_1, val_2)
|
self.enforce_pow_expression(cs, val_1, val_2)
|
||||||
@ -192,9 +189,6 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
|
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
|
||||||
self.enforce_pow_expression(cs, val_1, val_2)
|
self.enforce_pow_expression(cs, val_1, val_2)
|
||||||
}
|
}
|
||||||
(_, ConstrainedValue::FieldElement(num_2)) => {
|
|
||||||
Err(ExpressionError::InvalidExponent(num_2.to_string()))
|
|
||||||
}
|
|
||||||
(val_1, val_2) => Err(ExpressionError::IncompatibleTypes(format!(
|
(val_1, val_2) => Err(ExpressionError::IncompatibleTypes(format!(
|
||||||
"{} * {}",
|
"{} * {}",
|
||||||
val_1, val_2,
|
val_1, val_2,
|
||||||
@ -215,9 +209,9 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||||
Ok(Self::evaluate_integer_eq(num_1, num_2)?)
|
Ok(Self::evaluate_integer_eq(num_1, num_2)?)
|
||||||
}
|
}
|
||||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||||
// Self::field_eq(fe_1, fe_2)
|
Ok(ConstrainedValue::Boolean(Boolean::Constant(fe_1.eq(&fe_2))))
|
||||||
// }
|
}
|
||||||
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
|
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
|
||||||
Ok(ConstrainedValue::Boolean(Boolean::Constant(ge_1.eq(&ge_2))))
|
Ok(ConstrainedValue::Boolean(Boolean::Constant(ge_1.eq(&ge_2))))
|
||||||
}
|
}
|
||||||
@ -236,22 +230,23 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_geq_expression(
|
fn evaluate_ge_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
left: ConstrainedValue<F, G>,
|
left: ConstrainedValue<F, G>,
|
||||||
right: ConstrainedValue<F, G>,
|
right: ConstrainedValue<F, G>,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
match (left, right) {
|
match (left, right) {
|
||||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||||
// Self::field_geq(fe_1, fe_2)
|
let result = fe_1.ge(&fe_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)?;
|
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
|
||||||
self.evaluate_geq_expression(val_1, val_2)
|
self.evaluate_ge_expression(val_1, val_2)
|
||||||
}
|
}
|
||||||
(val_1, ConstrainedValue::Unresolved(string)) => {
|
(val_1, ConstrainedValue::Unresolved(string)) => {
|
||||||
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
|
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
|
||||||
self.evaluate_geq_expression(val_1, val_2)
|
self.evaluate_ge_expression(val_1, val_2)
|
||||||
}
|
}
|
||||||
(val_1, val_2) => Err(ExpressionError::IncompatibleTypes(format!(
|
(val_1, val_2) => Err(ExpressionError::IncompatibleTypes(format!(
|
||||||
"{} >= {}, values must be fields",
|
"{} >= {}, values must be fields",
|
||||||
@ -266,9 +261,10 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
right: ConstrainedValue<F, G>,
|
right: ConstrainedValue<F, G>,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
match (left, right) {
|
match (left, right) {
|
||||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||||
// Self::field_gt(fe_1, fe_2)
|
let result = fe_1.gt(&fe_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)?;
|
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
|
||||||
self.evaluate_gt_expression(val_1, val_2)
|
self.evaluate_gt_expression(val_1, val_2)
|
||||||
@ -284,22 +280,23 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_leq_expression(
|
fn evaluate_le_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
left: ConstrainedValue<F, G>,
|
left: ConstrainedValue<F, G>,
|
||||||
right: ConstrainedValue<F, G>,
|
right: ConstrainedValue<F, G>,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
match (left, right) {
|
match (left, right) {
|
||||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||||
// Self::field_leq(fe_1, fe_2)
|
let result = fe_1.le(&fe_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)?;
|
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
|
||||||
self.evaluate_leq_expression(val_1, val_2)
|
self.evaluate_le_expression(val_1, val_2)
|
||||||
}
|
}
|
||||||
(val_1, ConstrainedValue::Unresolved(string)) => {
|
(val_1, ConstrainedValue::Unresolved(string)) => {
|
||||||
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
|
let val_2 = ConstrainedValue::from_other(string, &val_1)?;
|
||||||
self.evaluate_leq_expression(val_1, val_2)
|
self.evaluate_le_expression(val_1, val_2)
|
||||||
}
|
}
|
||||||
(val_1, val_2) => Err(ExpressionError::IncompatibleTypes(format!(
|
(val_1, val_2) => Err(ExpressionError::IncompatibleTypes(format!(
|
||||||
"{} <= {}, values must be fields",
|
"{} <= {}, values must be fields",
|
||||||
@ -314,9 +311,10 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
right: ConstrainedValue<F, G>,
|
right: ConstrainedValue<F, G>,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
match (left, right) {
|
match (left, right) {
|
||||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||||
// Self::field_lt(fe_1, fe_2)
|
let result = fe_1.lt(&fe_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)?;
|
let val_1 = ConstrainedValue::from_other(string, &val_2)?;
|
||||||
self.evaluate_lt_expression(val_1, val_2)
|
self.evaluate_lt_expression(val_1, val_2)
|
||||||
@ -338,10 +336,10 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
expected_types: &Vec<Type<F>>,
|
expected_types: &Vec<Type>,
|
||||||
first: Expression<F>,
|
first: Expression,
|
||||||
second: Expression<F>,
|
second: Expression,
|
||||||
third: Expression<F>,
|
third: Expression,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let resolved_first = match self.enforce_expression(
|
let resolved_first = match self.enforce_expression(
|
||||||
cs,
|
cs,
|
||||||
@ -374,6 +372,10 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
Integer::conditionally_select(cs, &resolved_first, &integer_2, &integer_3)?;
|
Integer::conditionally_select(cs, &resolved_first, &integer_2, &integer_3)?;
|
||||||
Ok(ConstrainedValue::Integer(result))
|
Ok(ConstrainedValue::Integer(result))
|
||||||
}
|
}
|
||||||
|
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||||
|
let result = FieldType::conditionally_select(cs, &resolved_first, &fe_1, &fe_2)?;
|
||||||
|
Ok(ConstrainedValue::Field(result))
|
||||||
|
}
|
||||||
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
|
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
|
||||||
let result = G::conditionally_select(cs, &resolved_first, &ge_1, &ge_2)?;
|
let result = G::conditionally_select(cs, &resolved_first, &ge_1, &ge_2)?;
|
||||||
Ok(ConstrainedValue::Group(result))
|
Ok(ConstrainedValue::Group(result))
|
||||||
@ -390,8 +392,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
expected_types: &Vec<Type<F>>,
|
expected_types: &Vec<Type>,
|
||||||
array: Vec<Box<SpreadOrExpression<F>>>,
|
array: Vec<Box<SpreadOrExpression>>,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
// Check explicit array type dimension if given
|
// Check explicit array type dimension if given
|
||||||
let mut expected_types = expected_types.clone();
|
let mut expected_types = expected_types.clone();
|
||||||
@ -454,7 +456,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
index: Expression<F>,
|
index: Expression,
|
||||||
) -> Result<usize, ExpressionError> {
|
) -> Result<usize, ExpressionError> {
|
||||||
let expected_types = vec![Type::IntegerType(IntegerType::U32)];
|
let expected_types = vec![Type::IntegerType(IntegerType::U32)];
|
||||||
match self.enforce_branch(
|
match self.enforce_branch(
|
||||||
@ -474,9 +476,9 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
expected_types: &Vec<Type<F>>,
|
expected_types: &Vec<Type>,
|
||||||
array: Box<Expression<F>>,
|
array: Box<Expression>,
|
||||||
index: RangeOrExpression<F>,
|
index: RangeOrExpression,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let array = match self.enforce_branch(
|
let array = match self.enforce_branch(
|
||||||
cs,
|
cs,
|
||||||
@ -515,8 +517,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
identifier: Identifier<F>,
|
identifier: Identifier,
|
||||||
members: Vec<CircuitFieldDefinition<F>>,
|
members: Vec<CircuitFieldDefinition>,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let mut program_identifier = new_scope(file_scope.clone(), identifier.to_string());
|
let mut program_identifier = new_scope(file_scope.clone(), identifier.to_string());
|
||||||
|
|
||||||
@ -589,9 +591,9 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
expected_types: &Vec<Type<F>>,
|
expected_types: &Vec<Type>,
|
||||||
circuit_identifier: Box<Expression<F>>,
|
circuit_identifier: Box<Expression>,
|
||||||
circuit_member: Identifier<F>,
|
circuit_member: Identifier,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let (circuit_name, members) = match self.enforce_branch(
|
let (circuit_name, members) = match self.enforce_branch(
|
||||||
cs,
|
cs,
|
||||||
@ -650,9 +652,9 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
expected_types: &Vec<Type<F>>,
|
expected_types: &Vec<Type>,
|
||||||
circuit_identifier: Box<Expression<F>>,
|
circuit_identifier: Box<Expression>,
|
||||||
circuit_member: Identifier<F>,
|
circuit_member: Identifier,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
// Get defined circuit
|
// Get defined circuit
|
||||||
let circuit = match self.enforce_expression(
|
let circuit = match self.enforce_expression(
|
||||||
@ -704,9 +706,9 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
expected_types: &Vec<Type<F>>,
|
expected_types: &Vec<Type>,
|
||||||
function: Box<Expression<F>>,
|
function: Box<Expression>,
|
||||||
arguments: Vec<Expression<F>>,
|
arguments: Vec<Expression>,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let function_value = self.enforce_expression(
|
let function_value = self.enforce_expression(
|
||||||
cs,
|
cs,
|
||||||
@ -743,7 +745,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn enforce_number_implicit(
|
pub(crate) fn enforce_number_implicit(
|
||||||
expected_types: &Vec<Type<F>>,
|
expected_types: &Vec<Type>,
|
||||||
value: String,
|
value: String,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
if expected_types.len() == 1 {
|
if expected_types.len() == 1 {
|
||||||
@ -761,8 +763,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
expected_types: &Vec<Type<F>>,
|
expected_types: &Vec<Type>,
|
||||||
expression: Expression<F>,
|
expression: Expression,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
let mut branch =
|
let mut branch =
|
||||||
self.enforce_expression(cs, file_scope, function_scope, expected_types, expression)?;
|
self.enforce_expression(cs, file_scope, function_scope, expected_types, expression)?;
|
||||||
@ -778,9 +780,9 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
expected_types: &Vec<Type<F>>,
|
expected_types: &Vec<Type>,
|
||||||
left: Expression<F>,
|
left: Expression,
|
||||||
right: Expression<F>,
|
right: Expression,
|
||||||
) -> Result<(ConstrainedValue<F, G>, ConstrainedValue<F, G>), ExpressionError> {
|
) -> Result<(ConstrainedValue<F, G>, ConstrainedValue<F, G>), ExpressionError> {
|
||||||
let resolved_left = self.enforce_branch(
|
let resolved_left = self.enforce_branch(
|
||||||
cs,
|
cs,
|
||||||
@ -805,8 +807,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
expected_types: &Vec<Type<F>>,
|
expected_types: &Vec<Type>,
|
||||||
expression: Expression<F>,
|
expression: Expression,
|
||||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||||
match expression {
|
match expression {
|
||||||
// Variables
|
// Variables
|
||||||
@ -819,7 +821,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
|
|
||||||
// Values
|
// Values
|
||||||
Expression::Integer(integer) => Ok(Self::get_integer_constant(integer)),
|
Expression::Integer(integer) => Ok(Self::get_integer_constant(integer)),
|
||||||
Expression::FieldElement(fe) => Ok(Self::get_field_element_constant(fe)),
|
Expression::Field(field) => Ok(ConstrainedValue::Field(FieldType::constant(field)?)),
|
||||||
Expression::Group(group_affine) => {
|
Expression::Group(group_affine) => {
|
||||||
Ok(ConstrainedValue::Group(G::constant(group_affine)?))
|
Ok(ConstrainedValue::Group(G::constant(group_affine)?))
|
||||||
}
|
}
|
||||||
@ -932,7 +934,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
|
|
||||||
Ok(self.evaluate_eq_expression(resolved_left, resolved_right)?)
|
Ok(self.evaluate_eq_expression(resolved_left, resolved_right)?)
|
||||||
}
|
}
|
||||||
Expression::Geq(left, right) => {
|
Expression::Ge(left, right) => {
|
||||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||||
cs,
|
cs,
|
||||||
file_scope.clone(),
|
file_scope.clone(),
|
||||||
@ -942,7 +944,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
*right,
|
*right,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(self.evaluate_geq_expression(resolved_left, resolved_right)?)
|
Ok(self.evaluate_ge_expression(resolved_left, resolved_right)?)
|
||||||
}
|
}
|
||||||
Expression::Gt(left, right) => {
|
Expression::Gt(left, right) => {
|
||||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||||
@ -956,7 +958,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
|
|
||||||
Ok(self.evaluate_gt_expression(resolved_left, resolved_right)?)
|
Ok(self.evaluate_gt_expression(resolved_left, resolved_right)?)
|
||||||
}
|
}
|
||||||
Expression::Leq(left, right) => {
|
Expression::Le(left, right) => {
|
||||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||||
cs,
|
cs,
|
||||||
file_scope.clone(),
|
file_scope.clone(),
|
||||||
@ -966,7 +968,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
*right,
|
*right,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(self.evaluate_leq_expression(resolved_left, resolved_right)?)
|
Ok(self.evaluate_le_expression(resolved_left, resolved_right)?)
|
||||||
}
|
}
|
||||||
Expression::Lt(left, right) => {
|
Expression::Lt(left, right) => {
|
||||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||||
|
43
compiler/src/constraints/field.rs
Normal file
43
compiler/src/constraints/field.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
//! Methods to enforce constraints on field elements in a resolved Leo program.
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
constraints::ConstrainedValue, errors::FieldError, types::InputValue, FieldType, GroupType,
|
||||||
|
};
|
||||||
|
|
||||||
|
use snarkos_errors::gadgets::SynthesisError;
|
||||||
|
use snarkos_models::{
|
||||||
|
curves::{Field, PrimeField},
|
||||||
|
gadgets::{r1cs::ConstraintSystem, utilities::alloc::AllocGadget},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) fn field_from_input<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
|
||||||
|
cs: &mut CS,
|
||||||
|
name: String,
|
||||||
|
private: bool,
|
||||||
|
input_value: Option<InputValue>,
|
||||||
|
) -> Result<ConstrainedValue<F, G>, FieldError> {
|
||||||
|
// Check that the parameter value is the correct type
|
||||||
|
let field_option = match input_value {
|
||||||
|
Some(input) => {
|
||||||
|
if let InputValue::Field(field_string) = input {
|
||||||
|
Some(field_string)
|
||||||
|
} else {
|
||||||
|
return Err(FieldError::Invalid(input.to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check visibility of parameter
|
||||||
|
let field_value = if private {
|
||||||
|
FieldType::alloc(cs.ns(|| name), || {
|
||||||
|
field_option.ok_or(SynthesisError::AssignmentMissing)
|
||||||
|
})?
|
||||||
|
} else {
|
||||||
|
FieldType::alloc_input(cs.ns(|| name), || {
|
||||||
|
field_option.ok_or(SynthesisError::AssignmentMissing)
|
||||||
|
})?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ConstrainedValue::Field(field_value))
|
||||||
|
}
|
@ -1,471 +0,0 @@
|
|||||||
//! Methods to enforce constraints on field elements in a resolved Leo program.
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
constraints::{ConstrainedProgram, ConstrainedValue},
|
|
||||||
errors::FieldElementError,
|
|
||||||
types::{FieldElement, InputValue, Integer},
|
|
||||||
GroupType,
|
|
||||||
};
|
|
||||||
|
|
||||||
use snarkos_errors::gadgets::SynthesisError;
|
|
||||||
use snarkos_models::{
|
|
||||||
curves::{Field, PrimeField},
|
|
||||||
gadgets::r1cs::{ConstraintSystem, LinearCombination, Variable as R1CSVariable},
|
|
||||||
};
|
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> ConstrainedProgram<F, G, CS> {
|
|
||||||
pub(crate) fn field_element_from_input(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
name: String,
|
|
||||||
private: bool,
|
|
||||||
input_value: Option<InputValue<F>>,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, FieldElementError> {
|
|
||||||
// Check that the parameter value is the correct type
|
|
||||||
let field_option = match input_value {
|
|
||||||
Some(input) => {
|
|
||||||
if let InputValue::Field(fe) = input {
|
|
||||||
Some(fe)
|
|
||||||
} else {
|
|
||||||
return Err(FieldElementError::InvalidField(input.to_string()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check visibility of parameter
|
|
||||||
let field_value = if private {
|
|
||||||
cs.alloc(
|
|
||||||
|| name,
|
|
||||||
|| field_option.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
cs.alloc_input(
|
|
||||||
|| name,
|
|
||||||
|| field_option.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(ConstrainedValue::FieldElement(FieldElement::Allocated(
|
|
||||||
field_option,
|
|
||||||
field_value,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn get_field_element_constant(fe: FieldElement<F>) -> ConstrainedValue<F, G> {
|
|
||||||
ConstrainedValue::FieldElement(fe)
|
|
||||||
}
|
|
||||||
|
|
||||||
// pub(crate) fn field_eq(fe1: F, fe2: F) -> ResolvedValue<F> {
|
|
||||||
// ResolvedValue::Boolean(Boolean::Constant(fe1.eq(&fe2)))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub(crate) fn field_geq(fe1: F, fe2: F) -> ResolvedValue<F> {
|
|
||||||
// ResolvedValue::Boolean(Boolean::Constant(fe1.ge(&fe2)))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub(crate) fn field_gt(fe1: F, fe2: F) -> ResolvedValue<F> {
|
|
||||||
// ResolvedValue::Boolean(Boolean::Constant(fe1.gt(&fe2)))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub(crate) fn field_leq(fe1: F, fe2: F) -> ResolvedValue<F> {
|
|
||||||
// ResolvedValue::Boolean(Boolean::Constant(fe1.le(&fe2)))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub(crate) fn field_lt(fe1: F, fe2: F) -> ResolvedValue<F> {
|
|
||||||
// ResolvedValue::Boolean(Boolean::Constant(fe1.lt(&fe2)))
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub(crate) fn enforce_field_eq(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
fe_1: FieldElement<F>,
|
|
||||||
fe_2: FieldElement<F>,
|
|
||||||
) {
|
|
||||||
let mut lc = LinearCombination::zero();
|
|
||||||
|
|
||||||
match (fe_1, fe_2) {
|
|
||||||
(FieldElement::Constant(fe_1_constant), FieldElement::Constant(fe_2_constant)) => {
|
|
||||||
// lc = lc + (fe_1_constant * 1) - (fe_2_constant * 1)
|
|
||||||
// lc = lc + fe_1 - fe_2
|
|
||||||
lc = lc + (fe_1_constant, CS::one()) - (fe_2_constant, CS::one());
|
|
||||||
}
|
|
||||||
// else, return an allocated result
|
|
||||||
(
|
|
||||||
FieldElement::Allocated(_fe_1_value, fe_1_variable),
|
|
||||||
FieldElement::Constant(fe_2_constant),
|
|
||||||
) => {
|
|
||||||
// lc = lc + fe_1 - (fe_2_constant * 1)
|
|
||||||
// lc = lc + fe_1 - fe_2
|
|
||||||
lc = lc + fe_1_variable - (fe_2_constant, CS::one())
|
|
||||||
}
|
|
||||||
(
|
|
||||||
FieldElement::Constant(fe_1_constant),
|
|
||||||
FieldElement::Allocated(_fe_2_value, fe_2_variable),
|
|
||||||
) => {
|
|
||||||
// lc = lc + (fe_1_constant * 1) - fe_2
|
|
||||||
// lc = lc + fe_1 - fe_2
|
|
||||||
lc = lc + (fe_1_constant, CS::one()) - fe_2_variable
|
|
||||||
}
|
|
||||||
(
|
|
||||||
FieldElement::Allocated(_fe_1_value, fe_1_variable),
|
|
||||||
FieldElement::Allocated(_fe_2_value, fe_2_variable),
|
|
||||||
) => {
|
|
||||||
// lc = lc + fe_1 - fe_2
|
|
||||||
lc = lc + fe_1_variable - fe_2_variable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// enforce that the linear combination is zero
|
|
||||||
cs.enforce(|| "field equality", |lc| lc, |lc| lc, |_| lc);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn enforce_field_add(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
fe_1: FieldElement<F>,
|
|
||||||
fe_2: FieldElement<F>,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, FieldElementError> {
|
|
||||||
Ok(match (fe_1, fe_2) {
|
|
||||||
// if both constants, then return a constant result
|
|
||||||
(FieldElement::Constant(fe_1_constant), FieldElement::Constant(fe_2_constant)) => {
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Constant(
|
|
||||||
fe_1_constant.add(&fe_2_constant),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
// else, return an allocated result
|
|
||||||
(
|
|
||||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
|
||||||
FieldElement::Constant(fe_2_constant),
|
|
||||||
) => {
|
|
||||||
let sum_value: Option<F> = fe_1_value.map(|v| v.add(&fe_2_constant));
|
|
||||||
let sum_variable: R1CSVariable = cs.alloc(
|
|
||||||
|| "field addition",
|
|
||||||
|| sum_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "sum = 1 * (fe_1 + fe2)",
|
|
||||||
|lc| lc + CS::one(),
|
|
||||||
|lc| lc + fe_1_variable + (fe_2_constant, CS::one()),
|
|
||||||
|lc| lc + sum_variable.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Allocated(sum_value, sum_variable))
|
|
||||||
}
|
|
||||||
(
|
|
||||||
FieldElement::Constant(fe_1_constant),
|
|
||||||
FieldElement::Allocated(fe_2_value, fe_2_variable),
|
|
||||||
) => {
|
|
||||||
let sum_value: Option<F> = fe_2_value.map(|v| fe_1_constant.add(&v));
|
|
||||||
let sum_variable: R1CSVariable = cs.alloc(
|
|
||||||
|| "field addition",
|
|
||||||
|| sum_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "sum = 1 * (fe_1 + fe_2)",
|
|
||||||
|lc| lc + CS::one(),
|
|
||||||
|lc| lc + (fe_1_constant, CS::one()) + fe_2_variable,
|
|
||||||
|lc| lc + sum_variable.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Allocated(sum_value, sum_variable))
|
|
||||||
}
|
|
||||||
(
|
|
||||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
|
||||||
FieldElement::Allocated(fe_2_value, fe_2_variable),
|
|
||||||
) => {
|
|
||||||
let sum_value: Option<F> = match (fe_1_value, fe_2_value) {
|
|
||||||
(Some(fe_1_value), Some(fe_2_value)) => Some(fe_1_value.add(&fe_2_value)),
|
|
||||||
(_, _) => None,
|
|
||||||
};
|
|
||||||
let sum_variable: R1CSVariable = cs.alloc(
|
|
||||||
|| "field addition",
|
|
||||||
|| sum_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "sum = 1 * (fe_1 + fe_2)",
|
|
||||||
|lc| lc + CS::one(),
|
|
||||||
|lc| lc + fe_1_variable + fe_2_variable,
|
|
||||||
|lc| lc + sum_variable.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Allocated(sum_value, sum_variable))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn enforce_field_sub(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
fe_1: FieldElement<F>,
|
|
||||||
fe_2: FieldElement<F>,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, FieldElementError> {
|
|
||||||
Ok(match (fe_1, fe_2) {
|
|
||||||
// if both constants, then return a constant result
|
|
||||||
(FieldElement::Constant(fe_1_constant), FieldElement::Constant(fe_2_constant)) => {
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Constant(
|
|
||||||
fe_1_constant.sub(&fe_2_constant),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
// else, return an allocated result
|
|
||||||
(
|
|
||||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
|
||||||
FieldElement::Constant(fe_2_constant),
|
|
||||||
) => {
|
|
||||||
let sub_value: Option<F> = fe_1_value.map(|v| v.sub(&fe_2_constant));
|
|
||||||
let sub_variable: R1CSVariable = cs.alloc(
|
|
||||||
|| "field subtraction",
|
|
||||||
|| sub_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "sub = 1 * (fe_1 - fe2)",
|
|
||||||
|lc| lc + CS::one(),
|
|
||||||
|lc| lc + fe_1_variable - (fe_2_constant, CS::one()),
|
|
||||||
|lc| lc + sub_variable.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Allocated(sub_value, sub_variable))
|
|
||||||
}
|
|
||||||
(
|
|
||||||
FieldElement::Constant(fe_1_constant),
|
|
||||||
FieldElement::Allocated(fe_2_value, fe_2_variable),
|
|
||||||
) => {
|
|
||||||
let sub_value: Option<F> = fe_2_value.map(|v| fe_1_constant.sub(&v));
|
|
||||||
let sub_variable: R1CSVariable = cs.alloc(
|
|
||||||
|| "field subtraction",
|
|
||||||
|| sub_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "sub = 1 * (fe_1 - fe_2)",
|
|
||||||
|lc| lc + CS::one(),
|
|
||||||
|lc| lc + (fe_1_constant, CS::one()) - fe_2_variable,
|
|
||||||
|lc| lc + sub_variable.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Allocated(sub_value, sub_variable))
|
|
||||||
}
|
|
||||||
(
|
|
||||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
|
||||||
FieldElement::Allocated(fe_2_value, fe_2_variable),
|
|
||||||
) => {
|
|
||||||
let sub_value: Option<F> = match (fe_1_value, fe_2_value) {
|
|
||||||
(Some(fe_1_value), Some(fe_2_value)) => Some(fe_1_value.sub(&fe_2_value)),
|
|
||||||
(_, _) => None,
|
|
||||||
};
|
|
||||||
let sub_variable: R1CSVariable = cs.alloc(
|
|
||||||
|| "field subtraction",
|
|
||||||
|| sub_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "sub = 1 * (fe_1 - fe_2)",
|
|
||||||
|lc| lc + CS::one(),
|
|
||||||
|lc| lc + fe_1_variable - fe_2_variable,
|
|
||||||
|lc| lc + sub_variable.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Allocated(sub_value, sub_variable))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn enforce_field_mul(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
fe_1: FieldElement<F>,
|
|
||||||
fe_2: FieldElement<F>,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, FieldElementError> {
|
|
||||||
Ok(match (fe_1, fe_2) {
|
|
||||||
// if both constants, then return a constant result
|
|
||||||
(FieldElement::Constant(fe_1_constant), FieldElement::Constant(fe_2_constant)) => {
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Constant(
|
|
||||||
fe_1_constant.mul(&fe_2_constant),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
// else, return an allocated result
|
|
||||||
(
|
|
||||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
|
||||||
FieldElement::Constant(fe_2_constant),
|
|
||||||
) => {
|
|
||||||
let mul_value: Option<F> = fe_1_value.map(|v| v.mul(&fe_2_constant));
|
|
||||||
let mul_variable: R1CSVariable = cs.alloc(
|
|
||||||
|| "field multiplication",
|
|
||||||
|| mul_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "mul = fe_1 * fe_2",
|
|
||||||
|lc| lc + fe_1_variable,
|
|
||||||
|lc| lc + (fe_2_constant, CS::one()),
|
|
||||||
|lc| lc + mul_variable.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Allocated(mul_value, mul_variable))
|
|
||||||
}
|
|
||||||
(
|
|
||||||
FieldElement::Constant(fe_1_constant),
|
|
||||||
FieldElement::Allocated(fe_2_value, fe_2_variable),
|
|
||||||
) => {
|
|
||||||
let mul_value: Option<F> = fe_2_value.map(|v| fe_1_constant.mul(&v));
|
|
||||||
let mul_variable: R1CSVariable = cs.alloc(
|
|
||||||
|| "field multiplication",
|
|
||||||
|| mul_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "mul = fe_1 * fe_2",
|
|
||||||
|lc| lc + (fe_1_constant, CS::one()),
|
|
||||||
|lc| lc + fe_2_variable,
|
|
||||||
|lc| lc + mul_variable.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Allocated(mul_value, mul_variable))
|
|
||||||
}
|
|
||||||
(
|
|
||||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
|
||||||
FieldElement::Allocated(fe_2_value, fe_2_variable),
|
|
||||||
) => {
|
|
||||||
let mul_value: Option<F> = match (fe_1_value, fe_2_value) {
|
|
||||||
(Some(fe_1_value), Some(fe_2_value)) => Some(fe_1_value.mul(&fe_2_value)),
|
|
||||||
(_, _) => None,
|
|
||||||
};
|
|
||||||
let mul_variable: R1CSVariable = cs.alloc(
|
|
||||||
|| "field multiplication",
|
|
||||||
|| mul_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "mul = fe_1 * fe_2",
|
|
||||||
|lc| lc + fe_1_variable,
|
|
||||||
|lc| lc + fe_2_variable,
|
|
||||||
|lc| lc + mul_variable.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Allocated(mul_value, mul_variable))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn enforce_field_div(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
fe_1: FieldElement<F>,
|
|
||||||
fe_2: FieldElement<F>,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, FieldElementError> {
|
|
||||||
Ok(match (fe_1, fe_2) {
|
|
||||||
// if both constants, then return a constant result
|
|
||||||
(FieldElement::Constant(fe_1_constant), FieldElement::Constant(fe_2_constant)) => {
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Constant(
|
|
||||||
fe_1_constant.div(&fe_2_constant),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
// else, return an allocated result
|
|
||||||
(
|
|
||||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
|
||||||
FieldElement::Constant(fe_2_constant),
|
|
||||||
) => {
|
|
||||||
let div_value: Option<F> = fe_1_value.map(|v| v.div(&fe_2_constant));
|
|
||||||
let div_variable: R1CSVariable = cs.alloc(
|
|
||||||
|| "field division",
|
|
||||||
|| div_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
let fe_2_inverse_value = fe_2_constant.inverse().unwrap();
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "div = fe_1 * fe_2^-1",
|
|
||||||
|lc| lc + fe_1_variable,
|
|
||||||
|lc| lc + (fe_2_inverse_value, CS::one()),
|
|
||||||
|lc| lc + div_variable.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Allocated(div_value, div_variable))
|
|
||||||
}
|
|
||||||
(
|
|
||||||
FieldElement::Constant(fe_1_constant),
|
|
||||||
FieldElement::Allocated(fe_2_value, _fe_2_variable),
|
|
||||||
) => {
|
|
||||||
let div_value: Option<F> = fe_2_value.map(|v| fe_1_constant.div(&v));
|
|
||||||
let div_variable: R1CSVariable = cs.alloc(
|
|
||||||
|| "field division",
|
|
||||||
|| div_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
let fe_2_inverse_value = fe_2_value.map(|v| v.inverse().unwrap());
|
|
||||||
let fe_2_inverse_variable = cs.alloc(
|
|
||||||
|| "field inverse",
|
|
||||||
|| fe_2_inverse_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "div = fe_1 * fe_2^-1",
|
|
||||||
|lc| lc + (fe_1_constant, CS::one()),
|
|
||||||
|lc| lc + fe_2_inverse_variable,
|
|
||||||
|lc| lc + div_variable.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Allocated(div_value, div_variable))
|
|
||||||
}
|
|
||||||
(
|
|
||||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
|
||||||
FieldElement::Allocated(fe_2_value, _fe_2_variable),
|
|
||||||
) => {
|
|
||||||
let div_value: Option<F> = match (fe_1_value, fe_2_value) {
|
|
||||||
(Some(fe_1_value), Some(fe_2_value)) => Some(fe_1_value.div(&fe_2_value)),
|
|
||||||
(_, _) => None,
|
|
||||||
};
|
|
||||||
let div_variable: R1CSVariable = cs.alloc(
|
|
||||||
|| "field division",
|
|
||||||
|| div_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
let fe_2_inverse_value = fe_2_value.map(|v| v.inverse().unwrap());
|
|
||||||
let fe_2_inverse_variable = cs.alloc(
|
|
||||||
|| "field inverse",
|
|
||||||
|| fe_2_inverse_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
cs.enforce(
|
|
||||||
|| "div = fe_1 * fe_2^-1",
|
|
||||||
|lc| lc + fe_1_variable,
|
|
||||||
|lc| lc + fe_2_inverse_variable,
|
|
||||||
|lc| lc + div_variable.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Allocated(div_value, div_variable))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn enforce_field_pow(
|
|
||||||
&mut self,
|
|
||||||
cs: &mut CS,
|
|
||||||
fe_1: FieldElement<F>,
|
|
||||||
num: Integer,
|
|
||||||
) -> Result<ConstrainedValue<F, G>, FieldElementError> {
|
|
||||||
Ok(match fe_1 {
|
|
||||||
// if both constants, then return a constant result
|
|
||||||
FieldElement::Constant(fe_1_constant) => ConstrainedValue::FieldElement(
|
|
||||||
FieldElement::Constant(fe_1_constant.pow(&[num.to_usize() as u64])),
|
|
||||||
),
|
|
||||||
// else, return an allocated result
|
|
||||||
FieldElement::Allocated(fe_1_value, _fe_1_variable) => {
|
|
||||||
let pow_value: Option<F> = fe_1_value.map(|v| v.pow(&[num.to_usize() as u64]));
|
|
||||||
let pow_variable: R1CSVariable = cs.alloc(
|
|
||||||
|| "field exponentiation",
|
|
||||||
|| pow_value.ok_or(SynthesisError::AssignmentMissing),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// cs.enforce( //todo: find a linear combination for this
|
|
||||||
// || "pow = 1 + fe_1^num",
|
|
||||||
// |lc| lc + fe_1_variable,
|
|
||||||
// |lc| lc + (fe_2_inverse_value, CS::one()),
|
|
||||||
// |lc| lc + pow_variable.clone());
|
|
||||||
|
|
||||||
ConstrainedValue::FieldElement(FieldElement::Allocated(pow_value, pow_variable))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
constraints::{new_scope, ConstrainedProgram, ConstrainedValue},
|
constraints::{new_scope, ConstrainedProgram, ConstrainedValue},
|
||||||
errors::{FunctionError, ImportError},
|
errors::{FunctionError, ImportError},
|
||||||
group_from_input,
|
field_from_input, group_from_input,
|
||||||
types::{Expression, Function, Identifier, InputValue, Program, Type},
|
types::{Expression, Function, Identifier, InputValue, Program, Type},
|
||||||
GroupType,
|
GroupType,
|
||||||
};
|
};
|
||||||
@ -30,8 +30,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
scope: String,
|
scope: String,
|
||||||
caller_scope: String,
|
caller_scope: String,
|
||||||
function_name: String,
|
function_name: String,
|
||||||
expected_types: Vec<Type<F>>,
|
expected_types: Vec<Type>,
|
||||||
input: Expression<F>,
|
input: Expression,
|
||||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||||
// Evaluate the function input value as pass by value from the caller or
|
// Evaluate the function input value as pass by value from the caller or
|
||||||
// evaluate as an expression in the current function scope
|
// evaluate as an expression in the current function scope
|
||||||
@ -57,8 +57,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
scope: String,
|
scope: String,
|
||||||
caller_scope: String,
|
caller_scope: String,
|
||||||
function: Function<F>,
|
function: Function,
|
||||||
inputs: Vec<Expression<F>>,
|
inputs: Vec<Expression>,
|
||||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||||
let function_name = new_scope(scope.clone(), function.get_name());
|
let function_name = new_scope(scope.clone(), function.get_name());
|
||||||
|
|
||||||
@ -118,9 +118,9 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
name: String,
|
name: String,
|
||||||
private: bool,
|
private: bool,
|
||||||
array_type: Type<F>,
|
array_type: Type,
|
||||||
array_dimensions: Vec<usize>,
|
array_dimensions: Vec<usize>,
|
||||||
input_value: Option<InputValue<F>>,
|
input_value: Option<InputValue>,
|
||||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||||
let expected_length = array_dimensions[0];
|
let expected_length = array_dimensions[0];
|
||||||
let mut array_value = vec![];
|
let mut array_value = vec![];
|
||||||
@ -170,18 +170,16 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
fn allocate_main_function_input(
|
fn allocate_main_function_input(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
_type: Type<F>,
|
_type: Type,
|
||||||
name: String,
|
name: String,
|
||||||
private: bool,
|
private: bool,
|
||||||
input_value: Option<InputValue<F>>,
|
input_value: Option<InputValue>,
|
||||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||||
match _type {
|
match _type {
|
||||||
Type::IntegerType(integer_type) => {
|
Type::IntegerType(integer_type) => {
|
||||||
Ok(self.integer_from_parameter(cs, integer_type, name, private, input_value)?)
|
Ok(self.integer_from_parameter(cs, integer_type, name, private, input_value)?)
|
||||||
}
|
}
|
||||||
Type::FieldElement => {
|
Type::Field => Ok(field_from_input(cs, name, private, input_value)?),
|
||||||
Ok(self.field_element_from_input(cs, name, private, input_value)?)
|
|
||||||
}
|
|
||||||
Type::Group => Ok(group_from_input(cs, name, private, input_value)?),
|
Type::Group => Ok(group_from_input(cs, name, private, input_value)?),
|
||||||
Type::Boolean => Ok(self.bool_from_input(cs, name, private, input_value)?),
|
Type::Boolean => Ok(self.bool_from_input(cs, name, private, input_value)?),
|
||||||
Type::Array(_type, dimensions) => {
|
Type::Array(_type, dimensions) => {
|
||||||
@ -195,8 +193,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
scope: String,
|
scope: String,
|
||||||
function: Function<F>,
|
function: Function,
|
||||||
inputs: Vec<Option<InputValue<F>>>,
|
inputs: Vec<Option<InputValue>>,
|
||||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||||
let function_name = new_scope(scope.clone(), function.get_name());
|
let function_name = new_scope(scope.clone(), function.get_name());
|
||||||
|
|
||||||
@ -231,7 +229,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
pub(crate) fn resolve_definitions(
|
pub(crate) fn resolve_definitions(
|
||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
program: Program<F>,
|
program: Program,
|
||||||
) -> Result<(), ImportError> {
|
) -> Result<(), ImportError> {
|
||||||
let program_name = program.name.clone();
|
let program_name = program.name.clone();
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ pub(crate) fn group_from_input<F: Field + PrimeField, G: GroupType<F>, CS: Const
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
name: String,
|
name: String,
|
||||||
private: bool,
|
private: bool,
|
||||||
input_value: Option<InputValue<F>>,
|
input_value: Option<InputValue>,
|
||||||
) -> Result<ConstrainedValue<F, G>, GroupError> {
|
) -> Result<ConstrainedValue<F, G>, GroupError> {
|
||||||
// Check that the parameter value is the correct type
|
// Check that the parameter value is the correct type
|
||||||
let group_option = match input_value {
|
let group_option = match input_value {
|
||||||
|
@ -19,7 +19,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
&mut self,
|
&mut self,
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
scope: String,
|
scope: String,
|
||||||
import: Import<F>,
|
import: Import,
|
||||||
) -> Result<(), ImportError> {
|
) -> Result<(), ImportError> {
|
||||||
let path = current_dir().map_err(|error| ImportError::DirectoryError(error))?;
|
let path = current_dir().map_err(|error| ImportError::DirectoryError(error))?;
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
integer_type: IntegerType,
|
integer_type: IntegerType,
|
||||||
name: String,
|
name: String,
|
||||||
private: bool,
|
private: bool,
|
||||||
integer_value: Option<InputValue<F>>,
|
integer_value: Option<InputValue>,
|
||||||
) -> Result<ConstrainedValue<F, G>, IntegerError> {
|
) -> Result<ConstrainedValue<F, G>, IntegerError> {
|
||||||
// Check that the input value is the correct type
|
// Check that the input value is the correct type
|
||||||
let integer_option = match integer_value {
|
let integer_option = match integer_value {
|
||||||
|
@ -15,8 +15,8 @@ pub use import::*;
|
|||||||
pub mod integer;
|
pub mod integer;
|
||||||
pub use integer::*;
|
pub use integer::*;
|
||||||
|
|
||||||
pub mod field_element;
|
pub(crate) mod field;
|
||||||
pub use field_element::*;
|
pub(crate) use field::*;
|
||||||
|
|
||||||
pub(crate) mod group;
|
pub(crate) mod group;
|
||||||
pub(crate) use group::*;
|
pub(crate) use group::*;
|
||||||
@ -43,8 +43,8 @@ use snarkos_models::{
|
|||||||
|
|
||||||
pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
|
pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
|
||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
program: Program<F>,
|
program: Program,
|
||||||
parameters: Vec<Option<InputValue<F>>>,
|
parameters: Vec<Option<InputValue>>,
|
||||||
) -> Result<ConstrainedValue<F, G>, CompilerError> {
|
) -> Result<ConstrainedValue<F, G>, CompilerError> {
|
||||||
let mut resolved_program = ConstrainedProgram::new();
|
let mut resolved_program = ConstrainedProgram::new();
|
||||||
let program_name = program.get_name();
|
let program_name = program.get_name();
|
||||||
|
@ -13,11 +13,14 @@ use crate::{
|
|||||||
|
|
||||||
use snarkos_models::{
|
use snarkos_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean, utilities::uint32::UInt32},
|
gadgets::{
|
||||||
|
r1cs::ConstraintSystem,
|
||||||
|
utilities::{boolean::Boolean, eq::EqGadget, uint32::UInt32},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> ConstrainedProgram<F, G, CS> {
|
impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> ConstrainedProgram<F, G, CS> {
|
||||||
fn resolve_assignee(&mut self, scope: String, assignee: Assignee<F>) -> String {
|
fn resolve_assignee(&mut self, scope: String, assignee: Assignee) -> String {
|
||||||
match assignee {
|
match assignee {
|
||||||
Assignee::Identifier(name) => new_scope(scope, name.to_string()),
|
Assignee::Identifier(name) => new_scope(scope, name.to_string()),
|
||||||
Assignee::Array(array, _index) => self.resolve_assignee(scope, *array),
|
Assignee::Array(array, _index) => self.resolve_assignee(scope, *array),
|
||||||
@ -47,7 +50,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
name: String,
|
name: String,
|
||||||
range_or_expression: RangeOrExpression<F>,
|
range_or_expression: RangeOrExpression,
|
||||||
new_value: ConstrainedValue<F, G>,
|
new_value: ConstrainedValue<F, G>,
|
||||||
) -> Result<(), StatementError> {
|
) -> Result<(), StatementError> {
|
||||||
// Resolve index so we know if we are assigning to a single value or a range of values
|
// Resolve index so we know if we are assigning to a single value or a range of values
|
||||||
@ -91,7 +94,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
fn mutute_circuit_field(
|
fn mutute_circuit_field(
|
||||||
&mut self,
|
&mut self,
|
||||||
circuit_name: String,
|
circuit_name: String,
|
||||||
object_name: Identifier<F>,
|
object_name: Identifier,
|
||||||
new_value: ConstrainedValue<F, G>,
|
new_value: ConstrainedValue<F, G>,
|
||||||
) -> Result<(), StatementError> {
|
) -> Result<(), StatementError> {
|
||||||
match self.get_mutable_assignee(circuit_name)? {
|
match self.get_mutable_assignee(circuit_name)? {
|
||||||
@ -129,8 +132,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
assignee: Assignee<F>,
|
assignee: Assignee,
|
||||||
expression: Expression<F>,
|
expression: Expression,
|
||||||
) -> Result<(), StatementError> {
|
) -> Result<(), StatementError> {
|
||||||
// Get the name of the variable we are assigning to
|
// Get the name of the variable we are assigning to
|
||||||
let variable_name = self.resolve_assignee(function_scope.clone(), assignee.clone());
|
let variable_name = self.resolve_assignee(function_scope.clone(), assignee.clone());
|
||||||
@ -170,7 +173,7 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
fn store_definition(
|
fn store_definition(
|
||||||
&mut self,
|
&mut self,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
variable: Variable<F>,
|
variable: Variable,
|
||||||
mut value: ConstrainedValue<F, G>,
|
mut value: ConstrainedValue<F, G>,
|
||||||
) -> Result<(), StatementError> {
|
) -> Result<(), StatementError> {
|
||||||
// Store with given mutability
|
// Store with given mutability
|
||||||
@ -190,8 +193,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
variable: Variable<F>,
|
variable: Variable,
|
||||||
expression: Expression<F>,
|
expression: Expression,
|
||||||
) -> Result<(), StatementError> {
|
) -> Result<(), StatementError> {
|
||||||
let mut expected_types = vec![];
|
let mut expected_types = vec![];
|
||||||
if let Some(ref _type) = variable._type {
|
if let Some(ref _type) = variable._type {
|
||||||
@ -213,8 +216,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
variables: Vec<Variable<F>>,
|
variables: Vec<Variable>,
|
||||||
function: Expression<F>,
|
function: Expression,
|
||||||
) -> Result<(), StatementError> {
|
) -> Result<(), StatementError> {
|
||||||
let mut expected_types = vec![];
|
let mut expected_types = vec![];
|
||||||
for variable in variables.iter() {
|
for variable in variables.iter() {
|
||||||
@ -256,8 +259,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
expressions: Vec<Expression<F>>,
|
expressions: Vec<Expression>,
|
||||||
return_types: Vec<Type<F>>,
|
return_types: Vec<Type>,
|
||||||
) -> Result<ConstrainedValue<F, G>, StatementError> {
|
) -> Result<ConstrainedValue<F, G>, StatementError> {
|
||||||
// Make sure we return the correct number of values
|
// Make sure we return the correct number of values
|
||||||
if return_types.len() != expressions.len() {
|
if return_types.len() != expressions.len() {
|
||||||
@ -289,8 +292,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
statements: Vec<Statement<F>>,
|
statements: Vec<Statement>,
|
||||||
return_types: Vec<Type<F>>,
|
return_types: Vec<Type>,
|
||||||
) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
|
) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
|
||||||
let mut res = None;
|
let mut res = None;
|
||||||
// Evaluate statements and possibly return early
|
// Evaluate statements and possibly return early
|
||||||
@ -315,8 +318,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
statement: ConditionalStatement<F>,
|
statement: ConditionalStatement,
|
||||||
return_types: Vec<Type<F>>,
|
return_types: Vec<Type>,
|
||||||
) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
|
) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
|
||||||
let expected_types = vec![Type::Boolean];
|
let expected_types = vec![Type::Boolean];
|
||||||
let condition = match self.enforce_expression(
|
let condition = match self.enforce_expression(
|
||||||
@ -367,11 +370,11 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
index: Identifier<F>,
|
index: Identifier,
|
||||||
start: Integer,
|
start: Integer,
|
||||||
stop: Integer,
|
stop: Integer,
|
||||||
statements: Vec<Statement<F>>,
|
statements: Vec<Statement>,
|
||||||
return_types: Vec<Type<F>>,
|
return_types: Vec<Type>,
|
||||||
) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
|
) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
|
||||||
let mut res = None;
|
let mut res = None;
|
||||||
|
|
||||||
@ -413,8 +416,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||||
Self::enforce_integer_eq(cs, num_1, num_2)?
|
Self::enforce_integer_eq(cs, num_1, num_2)?
|
||||||
}
|
}
|
||||||
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
|
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
|
||||||
self.enforce_field_eq(cs, fe_1, fe_2)
|
fe_1.enforce_equal(cs, &fe_2)?
|
||||||
}
|
}
|
||||||
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
|
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
|
||||||
ge_1.enforce_equal(cs, &ge_2)?
|
ge_1.enforce_equal(cs, &ge_2)?
|
||||||
@ -424,17 +427,11 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
self.enforce_assert_eq_statement(cs, left, right)?;
|
self.enforce_assert_eq_statement(cs, left, right)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(val_1, val_2) => {
|
(val_1, val_2) => unimplemented!(
|
||||||
unimplemented!(
|
|
||||||
"assert eq not supported for given types {} == {}",
|
"assert eq not supported for given types {} == {}",
|
||||||
val_1,
|
val_1,
|
||||||
val_2
|
val_2
|
||||||
)
|
),
|
||||||
// return Err(StatementError::AssertEq(
|
|
||||||
// val_1.to_string(),
|
|
||||||
// val_2.to_string(),
|
|
||||||
// ))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,8 +440,8 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
file_scope: String,
|
file_scope: String,
|
||||||
function_scope: String,
|
function_scope: String,
|
||||||
statement: Statement<F>,
|
statement: Statement,
|
||||||
return_types: Vec<Type<F>>,
|
return_types: Vec<Type>,
|
||||||
) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
|
) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
|
||||||
let mut res = None;
|
let mut res = None;
|
||||||
match statement {
|
match statement {
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::ValueError,
|
errors::ValueError,
|
||||||
types::{Circuit, FieldElement, Function, Identifier, Integer, IntegerType, Type},
|
types::{Circuit, Function, Identifier, Integer, IntegerType, Type},
|
||||||
GroupType,
|
FieldType, GroupType,
|
||||||
};
|
};
|
||||||
|
|
||||||
use snarkos_models::{
|
use snarkos_models::{
|
||||||
@ -17,23 +17,23 @@ use std::fmt;
|
|||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct ConstrainedCircuitMember<F: Field + PrimeField, G: GroupType<F>>(
|
pub struct ConstrainedCircuitMember<F: Field + PrimeField, G: GroupType<F>>(
|
||||||
pub Identifier<F>,
|
pub Identifier,
|
||||||
pub ConstrainedValue<F, G>,
|
pub ConstrainedValue<F, G>,
|
||||||
);
|
);
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub enum ConstrainedValue<F: Field + PrimeField, G: GroupType<F>> {
|
pub enum ConstrainedValue<F: Field + PrimeField, G: GroupType<F>> {
|
||||||
Integer(Integer),
|
Integer(Integer),
|
||||||
FieldElement(FieldElement<F>),
|
Field(FieldType<F>),
|
||||||
Group(G),
|
Group(G),
|
||||||
Boolean(Boolean),
|
Boolean(Boolean),
|
||||||
|
|
||||||
Array(Vec<ConstrainedValue<F, G>>),
|
Array(Vec<ConstrainedValue<F, G>>),
|
||||||
|
|
||||||
CircuitDefinition(Circuit<F>),
|
CircuitDefinition(Circuit),
|
||||||
CircuitExpression(Identifier<F>, Vec<ConstrainedCircuitMember<F, G>>),
|
CircuitExpression(Identifier, Vec<ConstrainedCircuitMember<F, G>>),
|
||||||
|
|
||||||
Function(Option<Identifier<F>>, Function<F>), // (optional circuit identifier, function definition)
|
Function(Option<Identifier>, Function), // (optional circuit identifier, function definition)
|
||||||
Return(Vec<ConstrainedValue<F, G>>),
|
Return(Vec<ConstrainedValue<F, G>>),
|
||||||
|
|
||||||
Mutable(Box<ConstrainedValue<F, G>>),
|
Mutable(Box<ConstrainedValue<F, G>>),
|
||||||
@ -51,7 +51,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
|||||||
ConstrainedValue::from_type(value, &other_type)
|
ConstrainedValue::from_type(value, &other_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_type(value: String, _type: &Type<F>) -> Result<Self, ValueError> {
|
pub(crate) fn from_type(value: String, _type: &Type) -> Result<Self, ValueError> {
|
||||||
match _type {
|
match _type {
|
||||||
Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(match integer_type {
|
Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(match integer_type {
|
||||||
IntegerType::U8 => Integer::U8(UInt8::constant(value.parse::<u8>()?)),
|
IntegerType::U8 => Integer::U8(UInt8::constant(value.parse::<u8>()?)),
|
||||||
@ -60,9 +60,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
|||||||
IntegerType::U64 => Integer::U64(UInt64::constant(value.parse::<u64>()?)),
|
IntegerType::U64 => Integer::U64(UInt64::constant(value.parse::<u64>()?)),
|
||||||
IntegerType::U128 => Integer::U128(UInt128::constant(value.parse::<u128>()?)),
|
IntegerType::U128 => Integer::U128(UInt128::constant(value.parse::<u128>()?)),
|
||||||
})),
|
})),
|
||||||
Type::FieldElement => Ok(ConstrainedValue::FieldElement(FieldElement::Constant(
|
Type::Field => Ok(ConstrainedValue::Field(FieldType::constant(value)?)),
|
||||||
F::from_str(&value).unwrap_or_default(),
|
|
||||||
))),
|
|
||||||
Type::Group => Ok(ConstrainedValue::Group(G::constant(value)?)),
|
Type::Group => Ok(ConstrainedValue::Group(G::constant(value)?)),
|
||||||
Type::Boolean => Ok(ConstrainedValue::Boolean(Boolean::Constant(
|
Type::Boolean => Ok(ConstrainedValue::Boolean(Boolean::Constant(
|
||||||
value.parse::<bool>()?,
|
value.parse::<bool>()?,
|
||||||
@ -72,17 +70,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn to_type(&self) -> Type<F> {
|
pub(crate) fn to_type(&self) -> Type {
|
||||||
match self {
|
match self {
|
||||||
ConstrainedValue::Integer(integer) => Type::IntegerType(integer.get_type()),
|
ConstrainedValue::Integer(integer) => Type::IntegerType(integer.get_type()),
|
||||||
ConstrainedValue::FieldElement(_field) => Type::FieldElement,
|
ConstrainedValue::Field(_field) => Type::Field,
|
||||||
ConstrainedValue::Group(_group) => Type::Group,
|
ConstrainedValue::Group(_group) => Type::Group,
|
||||||
ConstrainedValue::Boolean(_bool) => Type::Boolean,
|
ConstrainedValue::Boolean(_bool) => Type::Boolean,
|
||||||
_ => unimplemented!("to type only implemented for primitives"),
|
_ => unimplemented!("to type only implemented for primitives"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_type(&mut self, types: &Vec<Type<F>>) -> Result<(), ValueError> {
|
pub(crate) fn resolve_type(&mut self, types: &Vec<Type>) -> Result<(), ValueError> {
|
||||||
if let ConstrainedValue::Unresolved(ref string) = self {
|
if let ConstrainedValue::Unresolved(ref string) = self {
|
||||||
if !types.is_empty() {
|
if !types.is_empty() {
|
||||||
*self = ConstrainedValue::from_type(string.clone(), &types[0])?
|
*self = ConstrainedValue::from_type(string.clone(), &types[0])?
|
||||||
@ -103,7 +101,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
ConstrainedValue::Integer(ref value) => write!(f, "{}", value),
|
ConstrainedValue::Integer(ref value) => write!(f, "{}", value),
|
||||||
ConstrainedValue::FieldElement(ref value) => write!(f, "{}", value),
|
ConstrainedValue::Field(ref value) => write!(f, "{:?}", value),
|
||||||
ConstrainedValue::Group(ref value) => write!(f, "{:?}", value),
|
ConstrainedValue::Group(ref value) => write!(f, "{:?}", value),
|
||||||
ConstrainedValue::Boolean(ref value) => write!(f, "{}", value.get_value().unwrap()),
|
ConstrainedValue::Boolean(ref value) => write!(f, "{}", value.get_value().unwrap()),
|
||||||
ConstrainedValue::Array(ref array) => {
|
ConstrainedValue::Array(ref array) => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
BooleanError, FieldElementError, FunctionError, GroupError, IntegerError, ValueError,
|
BooleanError, FieldError, FunctionError, GroupError, IntegerError, ValueError,
|
||||||
};
|
};
|
||||||
|
|
||||||
use snarkos_errors::gadgets::SynthesisError;
|
use snarkos_errors::gadgets::SynthesisError;
|
||||||
@ -28,7 +28,7 @@ pub enum ExpressionError {
|
|||||||
ParseIntError(ParseIntError),
|
ParseIntError(ParseIntError),
|
||||||
|
|
||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
FieldElementError(FieldElementError),
|
FieldError(FieldError),
|
||||||
|
|
||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
GroupError(#[from] GroupError),
|
GroupError(#[from] GroupError),
|
||||||
@ -128,9 +128,9 @@ impl From<ParseIntError> for ExpressionError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FieldElementError> for ExpressionError {
|
impl From<FieldError> for ExpressionError {
|
||||||
fn from(error: FieldElementError) -> Self {
|
fn from(error: FieldError) -> Self {
|
||||||
ExpressionError::FieldElementError(error)
|
ExpressionError::FieldError(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
use snarkos_errors::gadgets::SynthesisError;
|
use snarkos_errors::gadgets::SynthesisError;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum FieldElementError {
|
pub enum FieldError {
|
||||||
#[error("Expected field element parameter, got {}", _0)]
|
#[error("Expected field element parameter, got {}", _0)]
|
||||||
InvalidField(String),
|
Invalid(String),
|
||||||
|
|
||||||
|
#[error("No multiplicative inverse found for field {}", _0)]
|
||||||
|
NoInverse(String),
|
||||||
|
|
||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
SynthesisError(SynthesisError),
|
SynthesisError(SynthesisError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SynthesisError> for FieldElementError {
|
impl From<SynthesisError> for FieldError {
|
||||||
fn from(error: SynthesisError) -> Self {
|
fn from(error: SynthesisError) -> Self {
|
||||||
FieldElementError::SynthesisError(error)
|
FieldError::SynthesisError(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,5 @@
|
|||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
BooleanError, ExpressionError, FieldElementError, GroupError, IntegerError, StatementError,
|
BooleanError, ExpressionError, FieldError, GroupError, IntegerError, StatementError, ValueError,
|
||||||
ValueError,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
@ -27,7 +26,7 @@ pub enum FunctionError {
|
|||||||
IntegerError(IntegerError),
|
IntegerError(IntegerError),
|
||||||
|
|
||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
FieldElementError(FieldElementError),
|
FieldError(FieldError),
|
||||||
|
|
||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
GroupError(GroupError),
|
GroupError(GroupError),
|
||||||
@ -54,9 +53,9 @@ impl From<IntegerError> for FunctionError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FieldElementError> for FunctionError {
|
impl From<FieldError> for FunctionError {
|
||||||
fn from(error: FieldElementError) -> Self {
|
fn from(error: FieldError) -> Self {
|
||||||
FunctionError::FieldElementError(error)
|
FunctionError::FieldError(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@ pub use import::*;
|
|||||||
pub mod integer;
|
pub mod integer;
|
||||||
pub use integer::*;
|
pub use integer::*;
|
||||||
|
|
||||||
pub mod field_element;
|
pub mod field;
|
||||||
pub use field_element::*;
|
pub use field::*;
|
||||||
|
|
||||||
pub mod group;
|
pub mod group;
|
||||||
pub use group::*;
|
pub use group::*;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::errors::{BooleanError, ExpressionError, FieldElementError, IntegerError, ValueError};
|
use crate::errors::{BooleanError, ExpressionError, FieldError, IntegerError, ValueError};
|
||||||
|
|
||||||
use snarkos_errors::gadgets::SynthesisError;
|
use snarkos_errors::gadgets::SynthesisError;
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ pub enum StatementError {
|
|||||||
IntegerError(IntegerError),
|
IntegerError(IntegerError),
|
||||||
|
|
||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
FieldElementError(FieldElementError),
|
FieldError(FieldError),
|
||||||
|
|
||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
BooleanError(BooleanError),
|
BooleanError(BooleanError),
|
||||||
@ -81,9 +81,9 @@ impl From<IntegerError> for StatementError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FieldElementError> for StatementError {
|
impl From<FieldError> for StatementError {
|
||||||
fn from(error: FieldElementError) -> Self {
|
fn from(error: FieldError) -> Self {
|
||||||
StatementError::FieldElementError(error)
|
StatementError::FieldError(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::errors::{GroupError, IntegerError};
|
use crate::errors::{FieldError, GroupError, IntegerError};
|
||||||
|
|
||||||
use std::{num::ParseIntError, str::ParseBoolError};
|
use std::{num::ParseIntError, str::ParseBoolError};
|
||||||
|
|
||||||
@ -29,6 +29,9 @@ pub enum ValueError {
|
|||||||
|
|
||||||
#[error("{}", _0)]
|
#[error("{}", _0)]
|
||||||
GroupError(#[from] GroupError),
|
GroupError(#[from] GroupError),
|
||||||
|
|
||||||
|
#[error("{}", _0)]
|
||||||
|
FieldError(#[from] FieldError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ParseIntError> for ValueError {
|
impl From<ParseIntError> for ValueError {
|
||||||
|
289
compiler/src/field/mod.rs
Normal file
289
compiler/src/field/mod.rs
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
//! A data type that represents a field value
|
||||||
|
|
||||||
|
use crate::errors::FieldError;
|
||||||
|
|
||||||
|
use snarkos_errors::gadgets::SynthesisError;
|
||||||
|
use snarkos_models::gadgets::curves::FieldGadget;
|
||||||
|
use snarkos_models::{
|
||||||
|
curves::{Field, PrimeField},
|
||||||
|
gadgets::{
|
||||||
|
curves::FpGadget,
|
||||||
|
r1cs::ConstraintSystem,
|
||||||
|
utilities::{
|
||||||
|
alloc::AllocGadget,
|
||||||
|
boolean::Boolean,
|
||||||
|
eq::{ConditionalEqGadget, EqGadget},
|
||||||
|
select::CondSelectGadget,
|
||||||
|
uint8::UInt8,
|
||||||
|
ToBitsGadget, ToBytesGadget,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use std::borrow::Borrow;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum FieldType<F: Field + PrimeField> {
|
||||||
|
Constant(F),
|
||||||
|
Allocated(FpGadget<F>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField> FieldType<F> {
|
||||||
|
pub fn get_value(&self) -> Option<F> {
|
||||||
|
match self {
|
||||||
|
FieldType::Constant(field) => Some(*field),
|
||||||
|
FieldType::Allocated(gadget) => gadget.get_value(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn constant(string: String) -> Result<Self, FieldError> {
|
||||||
|
let value = F::from_str(&string).map_err(|_| FieldError::Invalid(string))?;
|
||||||
|
|
||||||
|
Ok(FieldType::Constant(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Self, FieldError> {
|
||||||
|
match (self, other) {
|
||||||
|
(FieldType::Constant(self_value), FieldType::Constant(other_value)) => {
|
||||||
|
Ok(FieldType::Constant(self_value.add(other_value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
(FieldType::Allocated(self_value), FieldType::Allocated(other_value)) => {
|
||||||
|
let result = self_value.add(cs, other_value)?;
|
||||||
|
|
||||||
|
Ok(FieldType::Allocated(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
(FieldType::Constant(constant_value), FieldType::Allocated(allocated_value))
|
||||||
|
| (FieldType::Allocated(allocated_value), FieldType::Constant(constant_value)) => Ok(
|
||||||
|
FieldType::Allocated(allocated_value.add_constant(cs, constant_value)?),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sub<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Self, FieldError> {
|
||||||
|
match (self, other) {
|
||||||
|
(FieldType::Constant(self_value), FieldType::Constant(other_value)) => {
|
||||||
|
Ok(FieldType::Constant(self_value.sub(other_value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
(FieldType::Allocated(self_value), FieldType::Allocated(other_value)) => {
|
||||||
|
let result = self_value.sub(cs, other_value)?;
|
||||||
|
|
||||||
|
Ok(FieldType::Allocated(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
(FieldType::Constant(constant_value), FieldType::Allocated(allocated_value))
|
||||||
|
| (FieldType::Allocated(allocated_value), FieldType::Constant(constant_value)) => Ok(
|
||||||
|
FieldType::Allocated(allocated_value.sub_constant(cs, constant_value)?),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mul<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Self, FieldError> {
|
||||||
|
match (self, other) {
|
||||||
|
(FieldType::Constant(self_value), FieldType::Constant(other_value)) => {
|
||||||
|
Ok(FieldType::Constant(self_value.mul(other_value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
(FieldType::Allocated(self_value), FieldType::Allocated(other_value)) => {
|
||||||
|
let result = self_value.mul(cs, other_value)?;
|
||||||
|
|
||||||
|
Ok(FieldType::Allocated(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
(FieldType::Constant(constant_value), FieldType::Allocated(allocated_value))
|
||||||
|
| (FieldType::Allocated(allocated_value), FieldType::Constant(constant_value)) => Ok(
|
||||||
|
FieldType::Allocated(allocated_value.mul_by_constant(cs, constant_value)?),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn div<CS: ConstraintSystem<F>>(
|
||||||
|
&self,
|
||||||
|
mut cs: CS,
|
||||||
|
other: &Self,
|
||||||
|
) -> Result<Self, FieldError> {
|
||||||
|
let inverse = match other {
|
||||||
|
FieldType::Constant(constant) => {
|
||||||
|
let constant_inverse = constant
|
||||||
|
.inverse()
|
||||||
|
.ok_or(FieldError::NoInverse(constant.to_string()))?;
|
||||||
|
FieldType::Constant(constant_inverse)
|
||||||
|
}
|
||||||
|
FieldType::Allocated(allocated) => {
|
||||||
|
let allocated_inverse = allocated.inverse(&mut cs)?;
|
||||||
|
FieldType::Allocated(allocated_inverse)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.mul(cs, &inverse)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alloc_helper<Fn: FnOnce() -> Result<T, SynthesisError>, T: Borrow<String>>(
|
||||||
|
value_gen: Fn,
|
||||||
|
) -> Result<F, SynthesisError> {
|
||||||
|
let field_string = match value_gen() {
|
||||||
|
Ok(value) => {
|
||||||
|
let string_value = value.borrow().clone();
|
||||||
|
Ok(string_value)
|
||||||
|
}
|
||||||
|
_ => Err(SynthesisError::AssignmentMissing),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
F::from_str(&field_string).map_err(|_| SynthesisError::AssignmentMissing)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocated<CS: ConstraintSystem<F>>(
|
||||||
|
&self,
|
||||||
|
mut cs: CS,
|
||||||
|
) -> Result<FpGadget<F>, SynthesisError> {
|
||||||
|
match self {
|
||||||
|
FieldType::Constant(constant) => {
|
||||||
|
FpGadget::alloc(&mut cs.ns(|| format!("{:?}", constant)), || Ok(constant))
|
||||||
|
}
|
||||||
|
FieldType::Allocated(allocated) => Ok(allocated.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField> AllocGadget<String, F> for FieldType<F> {
|
||||||
|
fn alloc<
|
||||||
|
Fn: FnOnce() -> Result<T, SynthesisError>,
|
||||||
|
T: Borrow<String>,
|
||||||
|
CS: ConstraintSystem<F>,
|
||||||
|
>(
|
||||||
|
cs: CS,
|
||||||
|
value_gen: Fn,
|
||||||
|
) -> Result<Self, SynthesisError> {
|
||||||
|
let value = FpGadget::alloc(cs, || Self::alloc_helper(value_gen))?;
|
||||||
|
|
||||||
|
Ok(FieldType::Allocated(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_input<
|
||||||
|
Fn: FnOnce() -> Result<T, SynthesisError>,
|
||||||
|
T: Borrow<String>,
|
||||||
|
CS: ConstraintSystem<F>,
|
||||||
|
>(
|
||||||
|
cs: CS,
|
||||||
|
value_gen: Fn,
|
||||||
|
) -> Result<Self, SynthesisError> {
|
||||||
|
let value = FpGadget::alloc_input(cs, || Self::alloc_helper(value_gen))?;
|
||||||
|
|
||||||
|
Ok(FieldType::Allocated(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField> PartialEq for FieldType<F> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
let self_value = self.get_value();
|
||||||
|
let other_value = other.get_value();
|
||||||
|
|
||||||
|
self_value.is_some() && other_value.is_some() && self_value.eq(&other_value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField> Eq for FieldType<F> {}
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField> PartialOrd for FieldType<F> {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
let self_value = self.get_value();
|
||||||
|
let other_value = other.get_value();
|
||||||
|
|
||||||
|
Option::from(self_value.cmp(&other_value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField> EqGadget<F> for FieldType<F> {}
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField> ConditionalEqGadget<F> for FieldType<F> {
|
||||||
|
fn conditional_enforce_equal<CS: ConstraintSystem<F>>(
|
||||||
|
&self,
|
||||||
|
mut cs: CS,
|
||||||
|
other: &Self,
|
||||||
|
condition: &Boolean,
|
||||||
|
) -> Result<(), SynthesisError> {
|
||||||
|
match (self, other) {
|
||||||
|
// c - c
|
||||||
|
(FieldType::Constant(self_value), FieldType::Constant(other_value)) => {
|
||||||
|
if self_value == other_value {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Err(SynthesisError::AssignmentMissing)
|
||||||
|
}
|
||||||
|
// a - a
|
||||||
|
(FieldType::Allocated(self_value), FieldType::Allocated(other_value)) => {
|
||||||
|
self_value.conditional_enforce_equal(cs, other_value, condition)
|
||||||
|
}
|
||||||
|
// c - a = a - c
|
||||||
|
(FieldType::Constant(constant_value), FieldType::Allocated(allocated_value))
|
||||||
|
| (FieldType::Allocated(allocated_value), FieldType::Constant(constant_value)) => {
|
||||||
|
let constant_gadget = FpGadget::from(&mut cs, constant_value);
|
||||||
|
|
||||||
|
constant_gadget.conditional_enforce_equal(cs, allocated_value, condition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cost() -> usize {
|
||||||
|
2 * <FpGadget<F> as ConditionalEqGadget<F>>::cost()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField> CondSelectGadget<F> for FieldType<F> {
|
||||||
|
fn conditionally_select<CS: ConstraintSystem<F>>(
|
||||||
|
mut cs: CS,
|
||||||
|
cond: &Boolean,
|
||||||
|
first: &Self,
|
||||||
|
second: &Self,
|
||||||
|
) -> Result<Self, SynthesisError> {
|
||||||
|
if let Boolean::Constant(cond) = *cond {
|
||||||
|
if cond {
|
||||||
|
Ok(first.clone())
|
||||||
|
} else {
|
||||||
|
Ok(second.clone())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let first_gadget = first.allocated(&mut cs)?;
|
||||||
|
let second_gadget = second.allocated(&mut cs)?;
|
||||||
|
let result = FpGadget::conditionally_select(cs, cond, &first_gadget, &second_gadget)?;
|
||||||
|
|
||||||
|
Ok(FieldType::Allocated(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cost() -> usize {
|
||||||
|
2 * <FpGadget<F> as CondSelectGadget<F>>::cost()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField> ToBitsGadget<F> for FieldType<F> {
|
||||||
|
fn to_bits<CS: ConstraintSystem<F>>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError> {
|
||||||
|
let self_gadget = self.allocated(&mut cs)?;
|
||||||
|
self_gadget.to_bits(cs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bits_strict<CS: ConstraintSystem<F>>(
|
||||||
|
&self,
|
||||||
|
mut cs: CS,
|
||||||
|
) -> Result<Vec<Boolean>, SynthesisError> {
|
||||||
|
let self_gadget = self.allocated(&mut cs)?;
|
||||||
|
self_gadget.to_bits_strict(cs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField> ToBytesGadget<F> for FieldType<F> {
|
||||||
|
fn to_bytes<CS: ConstraintSystem<F>>(&self, mut cs: CS) -> Result<Vec<UInt8>, SynthesisError> {
|
||||||
|
let self_gadget = self.allocated(&mut cs)?;
|
||||||
|
self_gadget.to_bytes(cs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bytes_strict<CS: ConstraintSystem<F>>(
|
||||||
|
&self,
|
||||||
|
mut cs: CS,
|
||||||
|
) -> Result<Vec<UInt8>, SynthesisError> {
|
||||||
|
let self_gadget = self.allocated(&mut cs)?;
|
||||||
|
self_gadget.to_bytes_strict(cs)
|
||||||
|
}
|
||||||
|
}
|
@ -214,7 +214,7 @@ impl ConditionalEqGadget<Fq> for EdwardsGroupType {
|
|||||||
}
|
}
|
||||||
// a - a
|
// a - a
|
||||||
(EdwardsGroupType::Allocated(self_value), EdwardsGroupType::Allocated(other_value)) => {
|
(EdwardsGroupType::Allocated(self_value), EdwardsGroupType::Allocated(other_value)) => {
|
||||||
return <EdwardsBlsGadget>::conditional_enforce_equal(
|
<EdwardsBlsGadget>::conditional_enforce_equal(
|
||||||
self_value,
|
self_value,
|
||||||
cs,
|
cs,
|
||||||
other_value,
|
other_value,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! A data type that represents members in the group formed by the set of affine points on a curve.
|
||||||
|
|
||||||
use crate::errors::GroupError;
|
use crate::errors::GroupError;
|
||||||
|
|
||||||
use snarkos_models::{
|
use snarkos_models::{
|
||||||
|
@ -2,23 +2,22 @@
|
|||||||
|
|
||||||
use crate::Identifier;
|
use crate::Identifier;
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ImportSymbol<F: Field + PrimeField> {
|
pub struct ImportSymbol {
|
||||||
pub symbol: Identifier<F>,
|
pub symbol: Identifier,
|
||||||
pub alias: Option<Identifier<F>>,
|
pub alias: Option<Identifier>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Import<F: Field + PrimeField> {
|
pub struct Import {
|
||||||
pub path_string: String,
|
pub path_string: String,
|
||||||
pub symbols: Vec<ImportSymbol<F>>,
|
pub symbols: Vec<ImportSymbol>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> Import<F> {
|
impl Import {
|
||||||
pub fn new(source: String, symbols: Vec<ImportSymbol<F>>) -> Import<F> {
|
pub fn new(source: String, symbols: Vec<ImportSymbol>) -> Import {
|
||||||
Import {
|
Import {
|
||||||
path_string: source,
|
path_string: source,
|
||||||
symbols,
|
symbols,
|
||||||
@ -51,7 +50,7 @@ impl<F: Field + PrimeField> Import<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for ImportSymbol<F> {
|
impl fmt::Display for ImportSymbol {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if self.alias.is_some() {
|
if self.alias.is_some() {
|
||||||
write!(f, "\t{} as {}", self.symbol, self.alias.as_ref().unwrap())
|
write!(f, "\t{} as {}", self.symbol, self.alias.as_ref().unwrap())
|
||||||
@ -61,13 +60,13 @@ impl<F: Field + PrimeField> fmt::Display for ImportSymbol<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> fmt::Display for Import<F> {
|
impl<'ast> fmt::Display for Import {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.format(f)
|
self.format(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> fmt::Debug for Import<F> {
|
impl<'ast> fmt::Debug for Import {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.format(f)
|
self.format(f)
|
||||||
}
|
}
|
||||||
|
@ -25,11 +25,11 @@ operation_and = { "&&" }
|
|||||||
operation_or = { "||" }
|
operation_or = { "||" }
|
||||||
|
|
||||||
operation_eq = { "==" }
|
operation_eq = { "==" }
|
||||||
operation_neq = { "!=" }
|
operation_ne = { "!=" }
|
||||||
|
|
||||||
operation_geq = { ">=" }
|
operation_ge = { ">=" }
|
||||||
operation_gt = { ">" }
|
operation_gt = { ">" }
|
||||||
operation_leq = { "<=" }
|
operation_le = { "<=" }
|
||||||
operation_lt = { "<" }
|
operation_lt = { "<" }
|
||||||
|
|
||||||
operation_add = { "+" }
|
operation_add = { "+" }
|
||||||
@ -39,9 +39,9 @@ operation_div = { "/" }
|
|||||||
operation_pow = { "**" }
|
operation_pow = { "**" }
|
||||||
|
|
||||||
operation_compare = _{
|
operation_compare = _{
|
||||||
operation_eq | operation_neq |
|
operation_eq | operation_ne |
|
||||||
operation_geq | operation_gt |
|
operation_ge | operation_gt |
|
||||||
operation_leq | operation_lt
|
operation_le | operation_lt
|
||||||
}
|
}
|
||||||
|
|
||||||
operation_binary = _{
|
operation_binary = _{
|
||||||
|
@ -22,6 +22,9 @@ pub use self::constraints::*;
|
|||||||
|
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
|
||||||
|
pub mod field;
|
||||||
|
pub use self::field::*;
|
||||||
|
|
||||||
pub mod group;
|
pub mod group;
|
||||||
pub use self::group::*;
|
pub use self::group::*;
|
||||||
|
|
||||||
|
@ -3,31 +3,21 @@
|
|||||||
|
|
||||||
use crate::Import;
|
use crate::Import;
|
||||||
|
|
||||||
use snarkos_models::{
|
use snarkos_models::gadgets::utilities::{
|
||||||
curves::{Field, PrimeField},
|
|
||||||
gadgets::{
|
|
||||||
r1cs::Variable as R1CSVariable,
|
|
||||||
utilities::{
|
|
||||||
boolean::Boolean, uint128::UInt128, uint16::UInt16, uint32::UInt32, uint64::UInt64,
|
boolean::Boolean, uint128::UInt128, uint16::UInt16, uint32::UInt32, uint64::UInt64,
|
||||||
uint8::UInt8,
|
uint8::UInt8,
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, marker::PhantomData};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// An identifier in the constrained program.
|
/// An identifier in the constrained program.
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Identifier<F: Field + PrimeField> {
|
pub struct Identifier {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub(crate) _engine: PhantomData<F>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> Identifier<F> {
|
impl Identifier {
|
||||||
pub fn new(name: String) -> Self {
|
pub fn new(name: String) -> Self {
|
||||||
Self {
|
Self { name }
|
||||||
name,
|
|
||||||
_engine: PhantomData::<F>,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_self(&self) -> bool {
|
pub fn is_self(&self) -> bool {
|
||||||
@ -37,10 +27,10 @@ impl<F: Field + PrimeField> Identifier<F> {
|
|||||||
|
|
||||||
/// A variable that is assigned to a value in the constrained program
|
/// A variable that is assigned to a value in the constrained program
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct Variable<F: Field + PrimeField> {
|
pub struct Variable {
|
||||||
pub identifier: Identifier<F>,
|
pub identifier: Identifier,
|
||||||
pub mutable: bool,
|
pub mutable: bool,
|
||||||
pub _type: Option<Type<F>>,
|
pub _type: Option<Type>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An integer type enum wrapping the integer value. Used only in expressions.
|
/// An integer type enum wrapping the integer value. Used only in expressions.
|
||||||
@ -53,79 +43,72 @@ pub enum Integer {
|
|||||||
U128(UInt128),
|
U128(UInt128),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A constant or allocated element in the field
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
|
||||||
pub enum FieldElement<F: Field + PrimeField> {
|
|
||||||
Constant(F),
|
|
||||||
Allocated(Option<F>, R1CSVariable),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Range or expression enum
|
/// Range or expression enum
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum RangeOrExpression<F: Field + PrimeField> {
|
pub enum RangeOrExpression {
|
||||||
Range(Option<Integer>, Option<Integer>),
|
Range(Option<Integer>, Option<Integer>),
|
||||||
Expression(Expression<F>),
|
Expression(Expression),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spread or expression
|
/// Spread or expression
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum SpreadOrExpression<F: Field + PrimeField> {
|
pub enum SpreadOrExpression {
|
||||||
Spread(Expression<F>),
|
Spread(Expression),
|
||||||
Expression(Expression<F>),
|
Expression(Expression),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expression that evaluates to a value
|
/// Expression that evaluates to a value
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum Expression<F: Field + PrimeField> {
|
pub enum Expression {
|
||||||
// Identifier
|
// Identifier
|
||||||
Identifier(Identifier<F>),
|
Identifier(Identifier),
|
||||||
|
|
||||||
// Values
|
// Values
|
||||||
Integer(Integer),
|
Integer(Integer),
|
||||||
FieldElement(FieldElement<F>),
|
Field(String),
|
||||||
Group(String),
|
Group(String),
|
||||||
Boolean(Boolean),
|
Boolean(Boolean),
|
||||||
Implicit(String),
|
Implicit(String),
|
||||||
|
|
||||||
// Number operations
|
// Number operations
|
||||||
Add(Box<Expression<F>>, Box<Expression<F>>),
|
Add(Box<Expression>, Box<Expression>),
|
||||||
Sub(Box<Expression<F>>, Box<Expression<F>>),
|
Sub(Box<Expression>, Box<Expression>),
|
||||||
Mul(Box<Expression<F>>, Box<Expression<F>>),
|
Mul(Box<Expression>, Box<Expression>),
|
||||||
Div(Box<Expression<F>>, Box<Expression<F>>),
|
Div(Box<Expression>, Box<Expression>),
|
||||||
Pow(Box<Expression<F>>, Box<Expression<F>>),
|
Pow(Box<Expression>, Box<Expression>),
|
||||||
|
|
||||||
// Boolean operations
|
// Boolean operations
|
||||||
Not(Box<Expression<F>>),
|
Not(Box<Expression>),
|
||||||
Or(Box<Expression<F>>, Box<Expression<F>>),
|
Or(Box<Expression>, Box<Expression>),
|
||||||
And(Box<Expression<F>>, Box<Expression<F>>),
|
And(Box<Expression>, Box<Expression>),
|
||||||
Eq(Box<Expression<F>>, Box<Expression<F>>),
|
Eq(Box<Expression>, Box<Expression>),
|
||||||
Geq(Box<Expression<F>>, Box<Expression<F>>),
|
Ge(Box<Expression>, Box<Expression>),
|
||||||
Gt(Box<Expression<F>>, Box<Expression<F>>),
|
Gt(Box<Expression>, Box<Expression>),
|
||||||
Leq(Box<Expression<F>>, Box<Expression<F>>),
|
Le(Box<Expression>, Box<Expression>),
|
||||||
Lt(Box<Expression<F>>, Box<Expression<F>>),
|
Lt(Box<Expression>, Box<Expression>),
|
||||||
|
|
||||||
// Conditionals
|
// Conditionals
|
||||||
IfElse(Box<Expression<F>>, Box<Expression<F>>, Box<Expression<F>>),
|
IfElse(Box<Expression>, Box<Expression>, Box<Expression>),
|
||||||
|
|
||||||
// Arrays
|
// Arrays
|
||||||
Array(Vec<Box<SpreadOrExpression<F>>>),
|
Array(Vec<Box<SpreadOrExpression>>),
|
||||||
ArrayAccess(Box<Expression<F>>, Box<RangeOrExpression<F>>), // (array name, range)
|
ArrayAccess(Box<Expression>, Box<RangeOrExpression>), // (array name, range)
|
||||||
|
|
||||||
// Circuits
|
// Circuits
|
||||||
Circuit(Identifier<F>, Vec<CircuitFieldDefinition<F>>),
|
Circuit(Identifier, Vec<CircuitFieldDefinition>),
|
||||||
CircuitMemberAccess(Box<Expression<F>>, Identifier<F>), // (declared circuit name, circuit member name)
|
CircuitMemberAccess(Box<Expression>, Identifier), // (declared circuit name, circuit member name)
|
||||||
CircuitStaticFunctionAccess(Box<Expression<F>>, Identifier<F>), // (defined circuit name, circuit static member name)
|
CircuitStaticFunctionAccess(Box<Expression>, Identifier), // (defined circuit name, circuit static member name)
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
FunctionCall(Box<Expression<F>>, Vec<Expression<F>>),
|
FunctionCall(Box<Expression>, Vec<Expression>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Definition assignee: v, arr[0..2], Point p.x
|
/// Definition assignee: v, arr[0..2], Point p.x
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum Assignee<F: Field + PrimeField> {
|
pub enum Assignee {
|
||||||
Identifier(Identifier<F>),
|
Identifier(Identifier),
|
||||||
Array(Box<Assignee<F>>, RangeOrExpression<F>),
|
Array(Box<Assignee>, RangeOrExpression),
|
||||||
CircuitField(Box<Assignee<F>>, Identifier<F>), // (circuit name, circuit field name)
|
CircuitField(Box<Assignee>, Identifier), // (circuit name, circuit field name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Explicit integer type
|
/// Explicit integer type
|
||||||
@ -140,17 +123,17 @@ pub enum IntegerType {
|
|||||||
|
|
||||||
/// Explicit type used for defining a variable or expression type
|
/// Explicit type used for defining a variable or expression type
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Type<F: Field + PrimeField> {
|
pub enum Type {
|
||||||
IntegerType(IntegerType),
|
IntegerType(IntegerType),
|
||||||
FieldElement,
|
Field,
|
||||||
Group,
|
Group,
|
||||||
Boolean,
|
Boolean,
|
||||||
Array(Box<Type<F>>, Vec<usize>),
|
Array(Box<Type>, Vec<usize>),
|
||||||
Circuit(Identifier<F>),
|
Circuit(Identifier),
|
||||||
SelfType,
|
SelfType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> Type<F> {
|
impl Type {
|
||||||
pub fn outer_dimension(&self, dimensions: &Vec<usize>) -> Self {
|
pub fn outer_dimension(&self, dimensions: &Vec<usize>) -> Self {
|
||||||
let _type = self.clone();
|
let _type = self.clone();
|
||||||
|
|
||||||
@ -179,79 +162,79 @@ impl<F: Field + PrimeField> Type<F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub enum ConditionalNestedOrEnd<F: Field + PrimeField> {
|
pub enum ConditionalNestedOrEnd {
|
||||||
Nested(Box<ConditionalStatement<F>>),
|
Nested(Box<ConditionalStatement>),
|
||||||
End(Vec<Statement<F>>),
|
End(Vec<Statement>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct ConditionalStatement<F: Field + PrimeField> {
|
pub struct ConditionalStatement {
|
||||||
pub condition: Expression<F>,
|
pub condition: Expression,
|
||||||
pub statements: Vec<Statement<F>>,
|
pub statements: Vec<Statement>,
|
||||||
pub next: Option<ConditionalNestedOrEnd<F>>,
|
pub next: Option<ConditionalNestedOrEnd>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Program statement that defines some action (or expression) to be carried out.
|
/// Program statement that defines some action (or expression) to be carried out.
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub enum Statement<F: Field + PrimeField> {
|
pub enum Statement {
|
||||||
Return(Vec<Expression<F>>),
|
Return(Vec<Expression>),
|
||||||
Definition(Variable<F>, Expression<F>),
|
Definition(Variable, Expression),
|
||||||
Assign(Assignee<F>, Expression<F>),
|
Assign(Assignee, Expression),
|
||||||
MultipleAssign(Vec<Variable<F>>, Expression<F>),
|
MultipleAssign(Vec<Variable>, Expression),
|
||||||
Conditional(ConditionalStatement<F>),
|
Conditional(ConditionalStatement),
|
||||||
For(Identifier<F>, Integer, Integer, Vec<Statement<F>>),
|
For(Identifier, Integer, Integer, Vec<Statement>),
|
||||||
AssertEq(Expression<F>, Expression<F>),
|
AssertEq(Expression, Expression),
|
||||||
Expression(Expression<F>),
|
Expression(Expression),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Circuits
|
/// Circuits
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct CircuitFieldDefinition<F: Field + PrimeField> {
|
pub struct CircuitFieldDefinition {
|
||||||
pub identifier: Identifier<F>,
|
pub identifier: Identifier,
|
||||||
pub expression: Expression<F>,
|
pub expression: Expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub enum CircuitMember<F: Field + PrimeField> {
|
pub enum CircuitMember {
|
||||||
CircuitField(Identifier<F>, Type<F>),
|
CircuitField(Identifier, Type),
|
||||||
CircuitFunction(bool, Function<F>),
|
CircuitFunction(bool, Function),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct Circuit<F: Field + PrimeField> {
|
pub struct Circuit {
|
||||||
pub identifier: Identifier<F>,
|
pub identifier: Identifier,
|
||||||
pub members: Vec<CircuitMember<F>>,
|
pub members: Vec<CircuitMember>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function parameters
|
/// Function parameters
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct InputModel<F: Field + PrimeField> {
|
pub struct InputModel {
|
||||||
pub identifier: Identifier<F>,
|
pub identifier: Identifier,
|
||||||
pub mutable: bool,
|
pub mutable: bool,
|
||||||
pub private: bool,
|
pub private: bool,
|
||||||
pub _type: Type<F>,
|
pub _type: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub enum InputValue<F: Field + PrimeField> {
|
pub enum InputValue {
|
||||||
Integer(usize),
|
Integer(usize),
|
||||||
Field(F),
|
Field(String),
|
||||||
Group(String),
|
Group(String),
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Array(Vec<InputValue<F>>),
|
Array(Vec<InputValue>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct Function<F: Field + PrimeField> {
|
pub struct Function {
|
||||||
pub function_name: Identifier<F>,
|
pub function_name: Identifier,
|
||||||
pub inputs: Vec<InputModel<F>>,
|
pub inputs: Vec<InputModel>,
|
||||||
pub returns: Vec<Type<F>>,
|
pub returns: Vec<Type>,
|
||||||
pub statements: Vec<Statement<F>>,
|
pub statements: Vec<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> Function<F> {
|
impl Function {
|
||||||
pub fn get_name(&self) -> String {
|
pub fn get_name(&self) -> String {
|
||||||
self.function_name.name.clone()
|
self.function_name.name.clone()
|
||||||
}
|
}
|
||||||
@ -259,15 +242,15 @@ impl<F: Field + PrimeField> Function<F> {
|
|||||||
|
|
||||||
/// A simple program with statement expressions, program arguments and program returns.
|
/// A simple program with statement expressions, program arguments and program returns.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Program<F: Field + PrimeField> {
|
pub struct Program {
|
||||||
pub name: Identifier<F>,
|
pub name: Identifier,
|
||||||
pub num_parameters: usize,
|
pub num_parameters: usize,
|
||||||
pub imports: Vec<Import<F>>,
|
pub imports: Vec<Import>,
|
||||||
pub circuits: HashMap<Identifier<F>, Circuit<F>>,
|
pub circuits: HashMap<Identifier, Circuit>,
|
||||||
pub functions: HashMap<Identifier<F>, Function<F>>,
|
pub functions: HashMap<Identifier, Function>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> Program<F> {
|
impl<'ast> Program {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: Identifier::new("".into()),
|
name: Identifier::new("".into()),
|
||||||
|
@ -2,25 +2,24 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Assignee, Circuit, CircuitMember, ConditionalNestedOrEnd, ConditionalStatement, Expression,
|
Assignee, Circuit, CircuitMember, ConditionalNestedOrEnd, ConditionalStatement, Expression,
|
||||||
FieldElement, Function, Identifier, InputModel, InputValue, Integer, IntegerType,
|
Function, Identifier, InputModel, InputValue, Integer, IntegerType, RangeOrExpression,
|
||||||
RangeOrExpression, SpreadOrExpression, Statement, Type, Variable,
|
SpreadOrExpression, Statement, Type, Variable,
|
||||||
};
|
};
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for Identifier<F> {
|
impl fmt::Display for Identifier {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", self.name)
|
write!(f, "{}", self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<F: Field + PrimeField> fmt::Debug for Identifier<F> {
|
impl fmt::Debug for Identifier {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", self.name)
|
write!(f, "{}", self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for Variable<F> {
|
impl fmt::Display for Variable {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if self.mutable {
|
if self.mutable {
|
||||||
write!(f, "mut ")?;
|
write!(f, "mut ")?;
|
||||||
@ -42,34 +41,7 @@ impl fmt::Display for Integer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> FieldElement<F> {
|
impl<'ast> fmt::Display for RangeOrExpression {
|
||||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
FieldElement::Constant(ref constant) => write!(f, "{}", constant),
|
|
||||||
FieldElement::Allocated(ref option, ref _r1cs_var) => {
|
|
||||||
if option.is_some() {
|
|
||||||
write!(f, "{}", option.unwrap())
|
|
||||||
} else {
|
|
||||||
write!(f, "allocated field")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for FieldElement<F> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
self.format(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Debug for FieldElement<F> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
self.format(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> fmt::Display for RangeOrExpression<F> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
RangeOrExpression::Range(ref from, ref to) => write!(
|
RangeOrExpression::Range(ref from, ref to) => write!(
|
||||||
@ -87,7 +59,7 @@ impl<'ast, F: Field + PrimeField> fmt::Display for RangeOrExpression<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for SpreadOrExpression<F> {
|
impl fmt::Display for SpreadOrExpression {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
SpreadOrExpression::Spread(ref spread) => write!(f, "...{}", spread),
|
SpreadOrExpression::Spread(ref spread) => write!(f, "...{}", spread),
|
||||||
@ -96,7 +68,7 @@ impl<F: Field + PrimeField> fmt::Display for SpreadOrExpression<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> fmt::Display for Expression<F> {
|
impl<'ast> fmt::Display for Expression {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
// Variables
|
// Variables
|
||||||
@ -104,7 +76,7 @@ impl<'ast, F: Field + PrimeField> fmt::Display for Expression<F> {
|
|||||||
|
|
||||||
// Values
|
// Values
|
||||||
Expression::Integer(ref integer) => write!(f, "{}", integer),
|
Expression::Integer(ref integer) => write!(f, "{}", integer),
|
||||||
Expression::FieldElement(ref field) => write!(f, "{}", field),
|
Expression::Field(ref field) => write!(f, "{}", field),
|
||||||
Expression::Group(ref group) => write!(f, "{}", group),
|
Expression::Group(ref group) => write!(f, "{}", group),
|
||||||
Expression::Boolean(ref bool) => write!(f, "{}", bool.get_value().unwrap()),
|
Expression::Boolean(ref bool) => write!(f, "{}", bool.get_value().unwrap()),
|
||||||
Expression::Implicit(ref value) => write!(f, "{}", value),
|
Expression::Implicit(ref value) => write!(f, "{}", value),
|
||||||
@ -121,9 +93,9 @@ impl<'ast, F: Field + PrimeField> fmt::Display for Expression<F> {
|
|||||||
Expression::Or(ref lhs, ref rhs) => write!(f, "{} || {}", lhs, rhs),
|
Expression::Or(ref lhs, ref rhs) => write!(f, "{} || {}", lhs, rhs),
|
||||||
Expression::And(ref lhs, ref rhs) => write!(f, "{} && {}", lhs, rhs),
|
Expression::And(ref lhs, ref rhs) => write!(f, "{} && {}", lhs, rhs),
|
||||||
Expression::Eq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
|
Expression::Eq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
|
||||||
Expression::Geq(ref lhs, ref rhs) => write!(f, "{} >= {}", lhs, rhs),
|
Expression::Ge(ref lhs, ref rhs) => write!(f, "{} >= {}", lhs, rhs),
|
||||||
Expression::Gt(ref lhs, ref rhs) => write!(f, "{} > {}", lhs, rhs),
|
Expression::Gt(ref lhs, ref rhs) => write!(f, "{} > {}", lhs, rhs),
|
||||||
Expression::Leq(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
|
Expression::Le(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
|
||||||
Expression::Lt(ref lhs, ref rhs) => write!(f, "{} < {}", lhs, rhs),
|
Expression::Lt(ref lhs, ref rhs) => write!(f, "{} < {}", lhs, rhs),
|
||||||
|
|
||||||
// Conditionals
|
// Conditionals
|
||||||
@ -177,7 +149,7 @@ impl<'ast, F: Field + PrimeField> fmt::Display for Expression<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for Assignee<F> {
|
impl fmt::Display for Assignee {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Assignee::Identifier(ref variable) => write!(f, "{}", variable),
|
Assignee::Identifier(ref variable) => write!(f, "{}", variable),
|
||||||
@ -189,7 +161,7 @@ impl<F: Field + PrimeField> fmt::Display for Assignee<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for ConditionalNestedOrEnd<F> {
|
impl fmt::Display for ConditionalNestedOrEnd {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
ConditionalNestedOrEnd::Nested(ref nested) => write!(f, "else {}", nested),
|
ConditionalNestedOrEnd::Nested(ref nested) => write!(f, "else {}", nested),
|
||||||
@ -204,7 +176,7 @@ impl<F: Field + PrimeField> fmt::Display for ConditionalNestedOrEnd<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for ConditionalStatement<F> {
|
impl fmt::Display for ConditionalStatement {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "if ({}) {{\n", self.condition)?;
|
write!(f, "if ({}) {{\n", self.condition)?;
|
||||||
for statement in self.statements.iter() {
|
for statement in self.statements.iter() {
|
||||||
@ -217,7 +189,7 @@ impl<F: Field + PrimeField> fmt::Display for ConditionalStatement<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for Statement<F> {
|
impl fmt::Display for Statement {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Statement::Return(ref statements) => {
|
Statement::Return(ref statements) => {
|
||||||
@ -274,11 +246,11 @@ impl fmt::Display for IntegerType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for Type<F> {
|
impl fmt::Display for Type {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Type::IntegerType(ref integer_type) => write!(f, "{}", integer_type),
|
Type::IntegerType(ref integer_type) => write!(f, "{}", integer_type),
|
||||||
Type::FieldElement => write!(f, "field"),
|
Type::Field => write!(f, "field"),
|
||||||
Type::Group => write!(f, "group"),
|
Type::Group => write!(f, "group"),
|
||||||
Type::Boolean => write!(f, "bool"),
|
Type::Boolean => write!(f, "bool"),
|
||||||
Type::Circuit(ref variable) => write!(f, "{}", variable),
|
Type::Circuit(ref variable) => write!(f, "{}", variable),
|
||||||
@ -294,7 +266,7 @@ impl<F: Field + PrimeField> fmt::Display for Type<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for CircuitMember<F> {
|
impl fmt::Display for CircuitMember {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
CircuitMember::CircuitField(ref identifier, ref _type) => {
|
CircuitMember::CircuitField(ref identifier, ref _type) => {
|
||||||
@ -310,7 +282,7 @@ impl<F: Field + PrimeField> fmt::Display for CircuitMember<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> Circuit<F> {
|
impl Circuit {
|
||||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "circuit {} {{ \n", self.identifier)?;
|
write!(f, "circuit {} {{ \n", self.identifier)?;
|
||||||
for field in self.members.iter() {
|
for field in self.members.iter() {
|
||||||
@ -320,19 +292,19 @@ impl<F: Field + PrimeField> Circuit<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl<F: Field + PrimeField> fmt::Display for Circuit<F> {// uncomment when we no longer print out Program
|
// impl fmt::Display for Circuit {// uncomment when we no longer print out Program
|
||||||
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
// self.format(f)
|
// self.format(f)
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Debug for Circuit<F> {
|
impl fmt::Debug for Circuit {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.format(f)
|
self.format(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for InputModel<F> {
|
impl fmt::Display for InputModel {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
// mut var: private bool
|
// mut var: private bool
|
||||||
if self.mutable {
|
if self.mutable {
|
||||||
@ -348,7 +320,7 @@ impl<F: Field + PrimeField> fmt::Display for InputModel<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for InputValue<F> {
|
impl fmt::Display for InputValue {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
InputValue::Integer(ref integer) => write!(f, "{}", integer),
|
InputValue::Integer(ref integer) => write!(f, "{}", integer),
|
||||||
@ -369,7 +341,7 @@ impl<F: Field + PrimeField> fmt::Display for InputValue<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> Function<F> {
|
impl Function {
|
||||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "function {}", self.function_name)?;
|
write!(f, "function {}", self.function_name)?;
|
||||||
let parameters = self
|
let parameters = self
|
||||||
@ -400,13 +372,13 @@ impl<F: Field + PrimeField> Function<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Display for Function<F> {
|
impl fmt::Display for Function {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.format(f)
|
self.format(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> fmt::Debug for Function<F> {
|
impl fmt::Debug for Function {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
self.format(f)
|
self.format(f)
|
||||||
}
|
}
|
||||||
|
@ -2,24 +2,21 @@
|
|||||||
|
|
||||||
use crate::{ast, types, Import, ImportSymbol};
|
use crate::{ast, types, Import, ImportSymbol};
|
||||||
|
|
||||||
use snarkos_models::{
|
use snarkos_models::gadgets::utilities::{
|
||||||
curves::{Field, PrimeField},
|
|
||||||
gadgets::utilities::{
|
|
||||||
boolean::Boolean, uint128::UInt128, uint16::UInt16, uint32::UInt32, uint64::UInt64,
|
boolean::Boolean, uint128::UInt128, uint16::UInt16, uint32::UInt32, uint64::UInt64,
|
||||||
uint8::UInt8,
|
uint8::UInt8,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// pest ast -> types::Identifier
|
/// pest ast -> types::Identifier
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Identifier<'ast>> for types::Identifier<F> {
|
impl<'ast> From<ast::Identifier<'ast>> for types::Identifier {
|
||||||
fn from(identifier: ast::Identifier<'ast>) -> Self {
|
fn from(identifier: ast::Identifier<'ast>) -> Self {
|
||||||
types::Identifier::new(identifier.value)
|
types::Identifier::new(identifier.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Identifier<'ast>> for types::Expression<F> {
|
impl<'ast> From<ast::Identifier<'ast>> for types::Expression {
|
||||||
fn from(identifier: ast::Identifier<'ast>) -> Self {
|
fn from(identifier: ast::Identifier<'ast>) -> Self {
|
||||||
types::Expression::Identifier(types::Identifier::from(identifier))
|
types::Expression::Identifier(types::Identifier::from(identifier))
|
||||||
}
|
}
|
||||||
@ -27,7 +24,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Identifier<'ast>> for types::Express
|
|||||||
|
|
||||||
/// pest ast -> types::Variable
|
/// pest ast -> types::Variable
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Variable<'ast>> for types::Variable<F> {
|
impl<'ast> From<ast::Variable<'ast>> for types::Variable {
|
||||||
fn from(variable: ast::Variable<'ast>) -> Self {
|
fn from(variable: ast::Variable<'ast>) -> Self {
|
||||||
types::Variable {
|
types::Variable {
|
||||||
identifier: types::Identifier::from(variable.identifier),
|
identifier: types::Identifier::from(variable.identifier),
|
||||||
@ -70,21 +67,19 @@ impl<'ast> types::Integer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Integer<'ast>> for types::Expression<F> {
|
impl<'ast> From<ast::Integer<'ast>> for types::Expression {
|
||||||
fn from(field: ast::Integer<'ast>) -> Self {
|
fn from(field: ast::Integer<'ast>) -> Self {
|
||||||
types::Expression::Integer(types::Integer::from(field.number, field._type))
|
types::Expression::Integer(types::Integer::from(field.number, field._type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::RangeOrExpression<'ast>>
|
impl<'ast> From<ast::RangeOrExpression<'ast>> for types::RangeOrExpression {
|
||||||
for types::RangeOrExpression<F>
|
|
||||||
{
|
|
||||||
fn from(range_or_expression: ast::RangeOrExpression<'ast>) -> Self {
|
fn from(range_or_expression: ast::RangeOrExpression<'ast>) -> Self {
|
||||||
match range_or_expression {
|
match range_or_expression {
|
||||||
ast::RangeOrExpression::Range(range) => {
|
ast::RangeOrExpression::Range(range) => {
|
||||||
let from = range
|
let from = range
|
||||||
.from
|
.from
|
||||||
.map(|from| match types::Expression::<F>::from(from.0) {
|
.map(|from| match types::Expression::from(from.0) {
|
||||||
types::Expression::Integer(number) => number,
|
types::Expression::Integer(number) => number,
|
||||||
types::Expression::Implicit(string) => {
|
types::Expression::Implicit(string) => {
|
||||||
types::Integer::from_implicit(string)
|
types::Integer::from_implicit(string)
|
||||||
@ -93,7 +88,7 @@ impl<'ast, F: Field + PrimeField> From<ast::RangeOrExpression<'ast>>
|
|||||||
unimplemented!("Range bounds should be integers, found {}", expression)
|
unimplemented!("Range bounds should be integers, found {}", expression)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let to = range.to.map(|to| match types::Expression::<F>::from(to.0) {
|
let to = range.to.map(|to| match types::Expression::from(to.0) {
|
||||||
types::Expression::Integer(number) => number,
|
types::Expression::Integer(number) => number,
|
||||||
types::Expression::Implicit(string) => types::Integer::from_implicit(string),
|
types::Expression::Implicit(string) => types::Integer::from_implicit(string),
|
||||||
expression => {
|
expression => {
|
||||||
@ -112,17 +107,15 @@ impl<'ast, F: Field + PrimeField> From<ast::RangeOrExpression<'ast>>
|
|||||||
|
|
||||||
/// pest ast -> types::Field
|
/// pest ast -> types::Field
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Field<'ast>> for types::Expression<F> {
|
impl<'ast> From<ast::Field<'ast>> for types::Expression {
|
||||||
fn from(field: ast::Field<'ast>) -> Self {
|
fn from(field: ast::Field<'ast>) -> Self {
|
||||||
types::Expression::FieldElement(types::FieldElement::Constant(
|
types::Expression::Field(field.number.value)
|
||||||
F::from_str(&field.number.value).unwrap_or_default(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// pest ast -> types::Group
|
/// pest ast -> types::Group
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Group<'ast>> for types::Expression<F> {
|
impl<'ast> From<ast::Group<'ast>> for types::Expression {
|
||||||
fn from(group: ast::Group<'ast>) -> Self {
|
fn from(group: ast::Group<'ast>) -> Self {
|
||||||
types::Expression::Group(group.to_string())
|
types::Expression::Group(group.to_string())
|
||||||
}
|
}
|
||||||
@ -130,7 +123,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Group<'ast>> for types::Expression<F
|
|||||||
|
|
||||||
/// pest ast -> types::Boolean
|
/// pest ast -> types::Boolean
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Boolean<'ast>> for types::Expression<F> {
|
impl<'ast> From<ast::Boolean<'ast>> for types::Expression {
|
||||||
fn from(boolean: ast::Boolean<'ast>) -> Self {
|
fn from(boolean: ast::Boolean<'ast>) -> Self {
|
||||||
types::Expression::Boolean(Boolean::Constant(
|
types::Expression::Boolean(Boolean::Constant(
|
||||||
boolean
|
boolean
|
||||||
@ -143,7 +136,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Boolean<'ast>> for types::Expression
|
|||||||
|
|
||||||
/// pest ast -> types::NumberImplicit
|
/// pest ast -> types::NumberImplicit
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::NumberImplicit<'ast>> for types::Expression<F> {
|
impl<'ast> From<ast::NumberImplicit<'ast>> for types::Expression {
|
||||||
fn from(number: ast::NumberImplicit<'ast>) -> Self {
|
fn from(number: ast::NumberImplicit<'ast>) -> Self {
|
||||||
types::Expression::Implicit(number.number.value)
|
types::Expression::Implicit(number.number.value)
|
||||||
}
|
}
|
||||||
@ -151,7 +144,7 @@ impl<'ast, F: Field + PrimeField> From<ast::NumberImplicit<'ast>> for types::Exp
|
|||||||
|
|
||||||
/// pest ast -> types::Expression
|
/// pest ast -> types::Expression
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Value<'ast>> for types::Expression<F> {
|
impl<'ast> From<ast::Value<'ast>> for types::Expression {
|
||||||
fn from(value: ast::Value<'ast>) -> Self {
|
fn from(value: ast::Value<'ast>) -> Self {
|
||||||
match value {
|
match value {
|
||||||
ast::Value::Integer(num) => types::Expression::from(num),
|
ast::Value::Integer(num) => types::Expression::from(num),
|
||||||
@ -163,15 +156,13 @@ impl<'ast, F: Field + PrimeField> From<ast::Value<'ast>> for types::Expression<F
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::NotExpression<'ast>> for types::Expression<F> {
|
impl<'ast> From<ast::NotExpression<'ast>> for types::Expression {
|
||||||
fn from(expression: ast::NotExpression<'ast>) -> Self {
|
fn from(expression: ast::NotExpression<'ast>) -> Self {
|
||||||
types::Expression::Not(Box::new(types::Expression::from(*expression.expression)))
|
types::Expression::Not(Box::new(types::Expression::from(*expression.expression)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::SpreadOrExpression<'ast>>
|
impl<'ast> From<ast::SpreadOrExpression<'ast>> for types::SpreadOrExpression {
|
||||||
for types::SpreadOrExpression<F>
|
|
||||||
{
|
|
||||||
fn from(s_or_e: ast::SpreadOrExpression<'ast>) -> Self {
|
fn from(s_or_e: ast::SpreadOrExpression<'ast>) -> Self {
|
||||||
match s_or_e {
|
match s_or_e {
|
||||||
ast::SpreadOrExpression::Spread(spread) => {
|
ast::SpreadOrExpression::Spread(spread) => {
|
||||||
@ -184,7 +175,7 @@ impl<'ast, F: Field + PrimeField> From<ast::SpreadOrExpression<'ast>>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::BinaryExpression<'ast>> for types::Expression<F> {
|
impl<'ast> From<ast::BinaryExpression<'ast>> for types::Expression {
|
||||||
fn from(expression: ast::BinaryExpression<'ast>) -> Self {
|
fn from(expression: ast::BinaryExpression<'ast>) -> Self {
|
||||||
match expression.operation {
|
match expression.operation {
|
||||||
// Boolean operations
|
// Boolean operations
|
||||||
@ -200,10 +191,10 @@ impl<'ast, F: Field + PrimeField> From<ast::BinaryExpression<'ast>> for types::E
|
|||||||
Box::new(types::Expression::from(*expression.left)),
|
Box::new(types::Expression::from(*expression.left)),
|
||||||
Box::new(types::Expression::from(*expression.right)),
|
Box::new(types::Expression::from(*expression.right)),
|
||||||
),
|
),
|
||||||
ast::BinaryOperator::Neq => {
|
ast::BinaryOperator::Ne => {
|
||||||
types::Expression::Not(Box::new(types::Expression::from(expression)))
|
types::Expression::Not(Box::new(types::Expression::from(expression)))
|
||||||
}
|
}
|
||||||
ast::BinaryOperator::Geq => types::Expression::Geq(
|
ast::BinaryOperator::Ge => types::Expression::Ge(
|
||||||
Box::new(types::Expression::from(*expression.left)),
|
Box::new(types::Expression::from(*expression.left)),
|
||||||
Box::new(types::Expression::from(*expression.right)),
|
Box::new(types::Expression::from(*expression.right)),
|
||||||
),
|
),
|
||||||
@ -211,7 +202,7 @@ impl<'ast, F: Field + PrimeField> From<ast::BinaryExpression<'ast>> for types::E
|
|||||||
Box::new(types::Expression::from(*expression.left)),
|
Box::new(types::Expression::from(*expression.left)),
|
||||||
Box::new(types::Expression::from(*expression.right)),
|
Box::new(types::Expression::from(*expression.right)),
|
||||||
),
|
),
|
||||||
ast::BinaryOperator::Leq => types::Expression::Leq(
|
ast::BinaryOperator::Le => types::Expression::Le(
|
||||||
Box::new(types::Expression::from(*expression.left)),
|
Box::new(types::Expression::from(*expression.left)),
|
||||||
Box::new(types::Expression::from(*expression.right)),
|
Box::new(types::Expression::from(*expression.right)),
|
||||||
),
|
),
|
||||||
@ -244,7 +235,7 @@ impl<'ast, F: Field + PrimeField> From<ast::BinaryExpression<'ast>> for types::E
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::TernaryExpression<'ast>> for types::Expression<F> {
|
impl<'ast> From<ast::TernaryExpression<'ast>> for types::Expression {
|
||||||
fn from(expression: ast::TernaryExpression<'ast>) -> Self {
|
fn from(expression: ast::TernaryExpression<'ast>) -> Self {
|
||||||
types::Expression::IfElse(
|
types::Expression::IfElse(
|
||||||
Box::new(types::Expression::from(*expression.first)),
|
Box::new(types::Expression::from(*expression.first)),
|
||||||
@ -254,7 +245,7 @@ impl<'ast, F: Field + PrimeField> From<ast::TernaryExpression<'ast>> for types::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::ArrayInlineExpression<'ast>> for types::Expression<F> {
|
impl<'ast> From<ast::ArrayInlineExpression<'ast>> for types::Expression {
|
||||||
fn from(array: ast::ArrayInlineExpression<'ast>) -> Self {
|
fn from(array: ast::ArrayInlineExpression<'ast>) -> Self {
|
||||||
types::Expression::Array(
|
types::Expression::Array(
|
||||||
array
|
array
|
||||||
@ -265,20 +256,16 @@ impl<'ast, F: Field + PrimeField> From<ast::ArrayInlineExpression<'ast>> for typ
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::ArrayInitializerExpression<'ast>>
|
impl<'ast> From<ast::ArrayInitializerExpression<'ast>> for types::Expression {
|
||||||
for types::Expression<F>
|
|
||||||
{
|
|
||||||
fn from(array: ast::ArrayInitializerExpression<'ast>) -> Self {
|
fn from(array: ast::ArrayInitializerExpression<'ast>) -> Self {
|
||||||
let count = types::Expression::<F>::get_count(array.count);
|
let count = types::Expression::get_count(array.count);
|
||||||
let expression = Box::new(types::SpreadOrExpression::from(*array.expression));
|
let expression = Box::new(types::SpreadOrExpression::from(*array.expression));
|
||||||
|
|
||||||
types::Expression::Array(vec![expression; count])
|
types::Expression::Array(vec![expression; count])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::CircuitField<'ast>>
|
impl<'ast> From<ast::CircuitField<'ast>> for types::CircuitFieldDefinition {
|
||||||
for types::CircuitFieldDefinition<F>
|
|
||||||
{
|
|
||||||
fn from(member: ast::CircuitField<'ast>) -> Self {
|
fn from(member: ast::CircuitField<'ast>) -> Self {
|
||||||
types::CircuitFieldDefinition {
|
types::CircuitFieldDefinition {
|
||||||
identifier: types::Identifier::from(member.identifier),
|
identifier: types::Identifier::from(member.identifier),
|
||||||
@ -287,22 +274,20 @@ impl<'ast, F: Field + PrimeField> From<ast::CircuitField<'ast>>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::CircuitInlineExpression<'ast>>
|
impl<'ast> From<ast::CircuitInlineExpression<'ast>> for types::Expression {
|
||||||
for types::Expression<F>
|
|
||||||
{
|
|
||||||
fn from(expression: ast::CircuitInlineExpression<'ast>) -> Self {
|
fn from(expression: ast::CircuitInlineExpression<'ast>) -> Self {
|
||||||
let variable = types::Identifier::from(expression.identifier);
|
let variable = types::Identifier::from(expression.identifier);
|
||||||
let members = expression
|
let members = expression
|
||||||
.members
|
.members
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|member| types::CircuitFieldDefinition::from(member))
|
.map(|member| types::CircuitFieldDefinition::from(member))
|
||||||
.collect::<Vec<types::CircuitFieldDefinition<F>>>();
|
.collect::<Vec<types::CircuitFieldDefinition>>();
|
||||||
|
|
||||||
types::Expression::Circuit(variable, members)
|
types::Expression::Circuit(variable, members)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::PostfixExpression<'ast>> for types::Expression<F> {
|
impl<'ast> From<ast::PostfixExpression<'ast>> for types::Expression {
|
||||||
fn from(expression: ast::PostfixExpression<'ast>) -> Self {
|
fn from(expression: ast::PostfixExpression<'ast>) -> Self {
|
||||||
let variable =
|
let variable =
|
||||||
types::Expression::Identifier(types::Identifier::from(expression.identifier));
|
types::Expression::Identifier(types::Identifier::from(expression.identifier));
|
||||||
@ -346,7 +331,7 @@ impl<'ast, F: Field + PrimeField> From<ast::PostfixExpression<'ast>> for types::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Expression<'ast>> for types::Expression<F> {
|
impl<'ast> From<ast::Expression<'ast>> for types::Expression {
|
||||||
fn from(expression: ast::Expression<'ast>) -> Self {
|
fn from(expression: ast::Expression<'ast>) -> Self {
|
||||||
match expression {
|
match expression {
|
||||||
ast::Expression::Value(value) => types::Expression::from(value),
|
ast::Expression::Value(value) => types::Expression::from(value),
|
||||||
@ -362,7 +347,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Expression<'ast>> for types::Express
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> types::Expression<F> {
|
impl<'ast> types::Expression {
|
||||||
fn get_count(count: ast::Value<'ast>) -> usize {
|
fn get_count(count: ast::Value<'ast>) -> usize {
|
||||||
match count {
|
match count {
|
||||||
ast::Value::Integer(integer) => integer
|
ast::Value::Integer(integer) => integer
|
||||||
@ -381,7 +366,7 @@ impl<'ast, F: Field + PrimeField> types::Expression<F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ast::Assignee -> types::Expression for operator assign statements
|
// ast::Assignee -> types::Expression for operator assign statements
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Assignee<'ast>> for types::Expression<F> {
|
impl<'ast> From<ast::Assignee<'ast>> for types::Expression {
|
||||||
fn from(assignee: ast::Assignee<'ast>) -> Self {
|
fn from(assignee: ast::Assignee<'ast>) -> Self {
|
||||||
let variable = types::Expression::Identifier(types::Identifier::from(assignee.identifier));
|
let variable = types::Expression::Identifier(types::Identifier::from(assignee.identifier));
|
||||||
|
|
||||||
@ -406,13 +391,13 @@ impl<'ast, F: Field + PrimeField> From<ast::Assignee<'ast>> for types::Expressio
|
|||||||
|
|
||||||
/// pest ast -> types::Assignee
|
/// pest ast -> types::Assignee
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Identifier<'ast>> for types::Assignee<F> {
|
impl<'ast> From<ast::Identifier<'ast>> for types::Assignee {
|
||||||
fn from(variable: ast::Identifier<'ast>) -> Self {
|
fn from(variable: ast::Identifier<'ast>) -> Self {
|
||||||
types::Assignee::Identifier(types::Identifier::from(variable))
|
types::Assignee::Identifier(types::Identifier::from(variable))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Assignee<'ast>> for types::Assignee<F> {
|
impl<'ast> From<ast::Assignee<'ast>> for types::Assignee {
|
||||||
fn from(assignee: ast::Assignee<'ast>) -> Self {
|
fn from(assignee: ast::Assignee<'ast>) -> Self {
|
||||||
let variable = types::Assignee::from(assignee.identifier);
|
let variable = types::Assignee::from(assignee.identifier);
|
||||||
|
|
||||||
@ -435,7 +420,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Assignee<'ast>> for types::Assignee<
|
|||||||
|
|
||||||
/// pest ast -> types::Statement
|
/// pest ast -> types::Statement
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::ReturnStatement<'ast>> for types::Statement<F> {
|
impl<'ast> From<ast::ReturnStatement<'ast>> for types::Statement {
|
||||||
fn from(statement: ast::ReturnStatement<'ast>) -> Self {
|
fn from(statement: ast::ReturnStatement<'ast>) -> Self {
|
||||||
types::Statement::Return(
|
types::Statement::Return(
|
||||||
statement
|
statement
|
||||||
@ -447,7 +432,7 @@ impl<'ast, F: Field + PrimeField> From<ast::ReturnStatement<'ast>> for types::St
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::DefinitionStatement<'ast>> for types::Statement<F> {
|
impl<'ast> From<ast::DefinitionStatement<'ast>> for types::Statement {
|
||||||
fn from(statement: ast::DefinitionStatement<'ast>) -> Self {
|
fn from(statement: ast::DefinitionStatement<'ast>) -> Self {
|
||||||
types::Statement::Definition(
|
types::Statement::Definition(
|
||||||
types::Variable::from(statement.variable),
|
types::Variable::from(statement.variable),
|
||||||
@ -456,7 +441,7 @@ impl<'ast, F: Field + PrimeField> From<ast::DefinitionStatement<'ast>> for types
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::AssignStatement<'ast>> for types::Statement<F> {
|
impl<'ast> From<ast::AssignStatement<'ast>> for types::Statement {
|
||||||
fn from(statement: ast::AssignStatement<'ast>) -> Self {
|
fn from(statement: ast::AssignStatement<'ast>) -> Self {
|
||||||
match statement.assign {
|
match statement.assign {
|
||||||
ast::OperationAssign::Assign(ref _assign) => types::Statement::Assign(
|
ast::OperationAssign::Assign(ref _assign) => types::Statement::Assign(
|
||||||
@ -512,9 +497,7 @@ impl<'ast, F: Field + PrimeField> From<ast::AssignStatement<'ast>> for types::St
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::MultipleAssignmentStatement<'ast>>
|
impl<'ast> From<ast::MultipleAssignmentStatement<'ast>> for types::Statement {
|
||||||
for types::Statement<F>
|
|
||||||
{
|
|
||||||
fn from(statement: ast::MultipleAssignmentStatement<'ast>) -> Self {
|
fn from(statement: ast::MultipleAssignmentStatement<'ast>) -> Self {
|
||||||
let variables = statement
|
let variables = statement
|
||||||
.variables
|
.variables
|
||||||
@ -536,9 +519,7 @@ impl<'ast, F: Field + PrimeField> From<ast::MultipleAssignmentStatement<'ast>>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::ConditionalNestedOrEnd<'ast>>
|
impl<'ast> From<ast::ConditionalNestedOrEnd<'ast>> for types::ConditionalNestedOrEnd {
|
||||||
for types::ConditionalNestedOrEnd<F>
|
|
||||||
{
|
|
||||||
fn from(statement: ast::ConditionalNestedOrEnd<'ast>) -> Self {
|
fn from(statement: ast::ConditionalNestedOrEnd<'ast>) -> Self {
|
||||||
match statement {
|
match statement {
|
||||||
ast::ConditionalNestedOrEnd::Nested(nested) => types::ConditionalNestedOrEnd::Nested(
|
ast::ConditionalNestedOrEnd::Nested(nested) => types::ConditionalNestedOrEnd::Nested(
|
||||||
@ -554,9 +535,7 @@ impl<'ast, F: Field + PrimeField> From<ast::ConditionalNestedOrEnd<'ast>>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::ConditionalStatement<'ast>>
|
impl<'ast> From<ast::ConditionalStatement<'ast>> for types::ConditionalStatement {
|
||||||
for types::ConditionalStatement<F>
|
|
||||||
{
|
|
||||||
fn from(statement: ast::ConditionalStatement<'ast>) -> Self {
|
fn from(statement: ast::ConditionalStatement<'ast>) -> Self {
|
||||||
types::ConditionalStatement {
|
types::ConditionalStatement {
|
||||||
condition: types::Expression::from(statement.condition),
|
condition: types::Expression::from(statement.condition),
|
||||||
@ -573,14 +552,14 @@ impl<'ast, F: Field + PrimeField> From<ast::ConditionalStatement<'ast>>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::ForStatement<'ast>> for types::Statement<F> {
|
impl<'ast> From<ast::ForStatement<'ast>> for types::Statement {
|
||||||
fn from(statement: ast::ForStatement<'ast>) -> Self {
|
fn from(statement: ast::ForStatement<'ast>) -> Self {
|
||||||
let from = match types::Expression::<F>::from(statement.start) {
|
let from = match types::Expression::from(statement.start) {
|
||||||
types::Expression::Integer(number) => number,
|
types::Expression::Integer(number) => number,
|
||||||
types::Expression::Implicit(string) => types::Integer::from_implicit(string),
|
types::Expression::Implicit(string) => types::Integer::from_implicit(string),
|
||||||
expression => unimplemented!("Range bounds should be integers, found {}", expression),
|
expression => unimplemented!("Range bounds should be integers, found {}", expression),
|
||||||
};
|
};
|
||||||
let to = match types::Expression::<F>::from(statement.stop) {
|
let to = match types::Expression::from(statement.stop) {
|
||||||
types::Expression::Integer(number) => number,
|
types::Expression::Integer(number) => number,
|
||||||
types::Expression::Implicit(string) => types::Integer::from_implicit(string),
|
types::Expression::Implicit(string) => types::Integer::from_implicit(string),
|
||||||
expression => unimplemented!("Range bounds should be integers, found {}", expression),
|
expression => unimplemented!("Range bounds should be integers, found {}", expression),
|
||||||
@ -599,7 +578,7 @@ impl<'ast, F: Field + PrimeField> From<ast::ForStatement<'ast>> for types::State
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::AssertStatement<'ast>> for types::Statement<F> {
|
impl<'ast> From<ast::AssertStatement<'ast>> for types::Statement {
|
||||||
fn from(statement: ast::AssertStatement<'ast>) -> Self {
|
fn from(statement: ast::AssertStatement<'ast>) -> Self {
|
||||||
match statement {
|
match statement {
|
||||||
ast::AssertStatement::AssertEq(assert_eq) => types::Statement::AssertEq(
|
ast::AssertStatement::AssertEq(assert_eq) => types::Statement::AssertEq(
|
||||||
@ -610,13 +589,13 @@ impl<'ast, F: Field + PrimeField> From<ast::AssertStatement<'ast>> for types::St
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::ExpressionStatement<'ast>> for types::Statement<F> {
|
impl<'ast> From<ast::ExpressionStatement<'ast>> for types::Statement {
|
||||||
fn from(statement: ast::ExpressionStatement<'ast>) -> Self {
|
fn from(statement: ast::ExpressionStatement<'ast>) -> Self {
|
||||||
types::Statement::Expression(types::Expression::from(statement.expression))
|
types::Statement::Expression(types::Expression::from(statement.expression))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Statement<'ast>> for types::Statement<F> {
|
impl<'ast> From<ast::Statement<'ast>> for types::Statement {
|
||||||
fn from(statement: ast::Statement<'ast>) -> Self {
|
fn from(statement: ast::Statement<'ast>) -> Self {
|
||||||
match statement {
|
match statement {
|
||||||
ast::Statement::Return(statement) => types::Statement::from(statement),
|
ast::Statement::Return(statement) => types::Statement::from(statement),
|
||||||
@ -647,39 +626,39 @@ impl From<ast::IntegerType> for types::IntegerType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Field + PrimeField> From<ast::BasicType> for types::Type<F> {
|
impl From<ast::BasicType> for types::Type {
|
||||||
fn from(basic_type: ast::BasicType) -> Self {
|
fn from(basic_type: ast::BasicType) -> Self {
|
||||||
match basic_type {
|
match basic_type {
|
||||||
ast::BasicType::Integer(_type) => {
|
ast::BasicType::Integer(_type) => {
|
||||||
types::Type::IntegerType(types::IntegerType::from(_type))
|
types::Type::IntegerType(types::IntegerType::from(_type))
|
||||||
}
|
}
|
||||||
ast::BasicType::Field(_type) => types::Type::FieldElement,
|
ast::BasicType::Field(_type) => types::Type::Field,
|
||||||
ast::BasicType::Group(_type) => types::Type::Group,
|
ast::BasicType::Group(_type) => types::Type::Group,
|
||||||
ast::BasicType::Boolean(_type) => types::Type::Boolean,
|
ast::BasicType::Boolean(_type) => types::Type::Boolean,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::ArrayType<'ast>> for types::Type<F> {
|
impl<'ast> From<ast::ArrayType<'ast>> for types::Type {
|
||||||
fn from(array_type: ast::ArrayType<'ast>) -> Self {
|
fn from(array_type: ast::ArrayType<'ast>) -> Self {
|
||||||
let element_type = Box::new(types::Type::from(array_type._type));
|
let element_type = Box::new(types::Type::from(array_type._type));
|
||||||
let dimensions = array_type
|
let dimensions = array_type
|
||||||
.dimensions
|
.dimensions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|row| types::Expression::<F>::get_count(row))
|
.map(|row| types::Expression::get_count(row))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
types::Type::Array(element_type, dimensions)
|
types::Type::Array(element_type, dimensions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::CircuitType<'ast>> for types::Type<F> {
|
impl<'ast> From<ast::CircuitType<'ast>> for types::Type {
|
||||||
fn from(circuit_type: ast::CircuitType<'ast>) -> Self {
|
fn from(circuit_type: ast::CircuitType<'ast>) -> Self {
|
||||||
types::Type::Circuit(types::Identifier::from(circuit_type.identifier))
|
types::Type::Circuit(types::Identifier::from(circuit_type.identifier))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Type<'ast>> for types::Type<F> {
|
impl<'ast> From<ast::Type<'ast>> for types::Type {
|
||||||
fn from(_type: ast::Type<'ast>) -> Self {
|
fn from(_type: ast::Type<'ast>) -> Self {
|
||||||
match _type {
|
match _type {
|
||||||
ast::Type::Basic(_type) => types::Type::from(_type),
|
ast::Type::Basic(_type) => types::Type::from(_type),
|
||||||
@ -692,9 +671,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Type<'ast>> for types::Type<F> {
|
|||||||
|
|
||||||
/// pest ast -> types::Circuit
|
/// pest ast -> types::Circuit
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::CircuitFieldDefinition<'ast>>
|
impl<'ast> From<ast::CircuitFieldDefinition<'ast>> for types::CircuitMember {
|
||||||
for types::CircuitMember<F>
|
|
||||||
{
|
|
||||||
fn from(circuit_value: ast::CircuitFieldDefinition<'ast>) -> Self {
|
fn from(circuit_value: ast::CircuitFieldDefinition<'ast>) -> Self {
|
||||||
types::CircuitMember::CircuitField(
|
types::CircuitMember::CircuitField(
|
||||||
types::Identifier::from(circuit_value.identifier),
|
types::Identifier::from(circuit_value.identifier),
|
||||||
@ -703,7 +680,7 @@ impl<'ast, F: Field + PrimeField> From<ast::CircuitFieldDefinition<'ast>>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::CircuitFunction<'ast>> for types::CircuitMember<F> {
|
impl<'ast> From<ast::CircuitFunction<'ast>> for types::CircuitMember {
|
||||||
fn from(circuit_function: ast::CircuitFunction<'ast>) -> Self {
|
fn from(circuit_function: ast::CircuitFunction<'ast>) -> Self {
|
||||||
types::CircuitMember::CircuitFunction(
|
types::CircuitMember::CircuitFunction(
|
||||||
circuit_function._static.is_some(),
|
circuit_function._static.is_some(),
|
||||||
@ -712,7 +689,7 @@ impl<'ast, F: Field + PrimeField> From<ast::CircuitFunction<'ast>> for types::Ci
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::CircuitMember<'ast>> for types::CircuitMember<F> {
|
impl<'ast> From<ast::CircuitMember<'ast>> for types::CircuitMember {
|
||||||
fn from(object: ast::CircuitMember<'ast>) -> Self {
|
fn from(object: ast::CircuitMember<'ast>) -> Self {
|
||||||
match object {
|
match object {
|
||||||
ast::CircuitMember::CircuitFieldDefinition(circuit_value) => {
|
ast::CircuitMember::CircuitFieldDefinition(circuit_value) => {
|
||||||
@ -725,7 +702,7 @@ impl<'ast, F: Field + PrimeField> From<ast::CircuitMember<'ast>> for types::Circ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Circuit<'ast>> for types::Circuit<F> {
|
impl<'ast> From<ast::Circuit<'ast>> for types::Circuit {
|
||||||
fn from(circuit: ast::Circuit<'ast>) -> Self {
|
fn from(circuit: ast::Circuit<'ast>) -> Self {
|
||||||
let variable = types::Identifier::from(circuit.identifier);
|
let variable = types::Identifier::from(circuit.identifier);
|
||||||
let members = circuit
|
let members = circuit
|
||||||
@ -743,7 +720,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Circuit<'ast>> for types::Circuit<F>
|
|||||||
|
|
||||||
/// pest ast -> function types::Parameters
|
/// pest ast -> function types::Parameters
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::InputModel<'ast>> for types::InputModel<F> {
|
impl<'ast> From<ast::InputModel<'ast>> for types::InputModel {
|
||||||
fn from(parameter: ast::InputModel<'ast>) -> Self {
|
fn from(parameter: ast::InputModel<'ast>) -> Self {
|
||||||
types::InputModel {
|
types::InputModel {
|
||||||
identifier: types::Identifier::from(parameter.identifier),
|
identifier: types::Identifier::from(parameter.identifier),
|
||||||
@ -759,7 +736,7 @@ impl<'ast, F: Field + PrimeField> From<ast::InputModel<'ast>> for types::InputMo
|
|||||||
|
|
||||||
/// pest ast -> types::Function
|
/// pest ast -> types::Function
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Function<'ast>> for types::Function<F> {
|
impl<'ast> From<ast::Function<'ast>> for types::Function {
|
||||||
fn from(function_definition: ast::Function<'ast>) -> Self {
|
fn from(function_definition: ast::Function<'ast>) -> Self {
|
||||||
let function_name = types::Identifier::from(function_definition.function_name);
|
let function_name = types::Identifier::from(function_definition.function_name);
|
||||||
let parameters = function_definition
|
let parameters = function_definition
|
||||||
@ -789,7 +766,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Function<'ast>> for types::Function<
|
|||||||
|
|
||||||
/// pest ast -> Import
|
/// pest ast -> Import
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::ImportSymbol<'ast>> for ImportSymbol<F> {
|
impl<'ast> From<ast::ImportSymbol<'ast>> for ImportSymbol {
|
||||||
fn from(symbol: ast::ImportSymbol<'ast>) -> Self {
|
fn from(symbol: ast::ImportSymbol<'ast>) -> Self {
|
||||||
ImportSymbol {
|
ImportSymbol {
|
||||||
symbol: types::Identifier::from(symbol.value),
|
symbol: types::Identifier::from(symbol.value),
|
||||||
@ -798,7 +775,7 @@ impl<'ast, F: Field + PrimeField> From<ast::ImportSymbol<'ast>> for ImportSymbol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> From<ast::Import<'ast>> for Import<F> {
|
impl<'ast> From<ast::Import<'ast>> for Import {
|
||||||
fn from(import: ast::Import<'ast>) -> Self {
|
fn from(import: ast::Import<'ast>) -> Self {
|
||||||
Import {
|
Import {
|
||||||
path_string: import.source.value,
|
path_string: import.source.value,
|
||||||
@ -813,14 +790,14 @@ impl<'ast, F: Field + PrimeField> From<ast::Import<'ast>> for Import<F> {
|
|||||||
|
|
||||||
/// pest ast -> types::Program
|
/// pest ast -> types::Program
|
||||||
|
|
||||||
impl<'ast, F: Field + PrimeField> types::Program<F> {
|
impl<'ast> types::Program {
|
||||||
pub fn from(file: ast::File<'ast>, name: String) -> Self {
|
pub fn from(file: ast::File<'ast>, name: String) -> Self {
|
||||||
// Compiled ast -> aleo program representation
|
// Compiled ast -> aleo program representation
|
||||||
let imports = file
|
let imports = file
|
||||||
.imports
|
.imports
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|import| Import::from(import))
|
.map(|import| Import::from(import))
|
||||||
.collect::<Vec<Import<F>>>();
|
.collect::<Vec<Import>>();
|
||||||
|
|
||||||
let mut circuits = HashMap::new();
|
let mut circuits = HashMap::new();
|
||||||
let mut functions = HashMap::new();
|
let mut functions = HashMap::new();
|
||||||
|
@ -8,22 +8,23 @@ use snarkos_models::gadgets::utilities::boolean::Boolean;
|
|||||||
|
|
||||||
const DIRECTORY_NAME: &str = "tests/boolean/";
|
const DIRECTORY_NAME: &str = "tests/boolean/";
|
||||||
|
|
||||||
pub fn output_true(program: EdwardsTestCompiler) {
|
pub fn output_expected_boolean(program: EdwardsTestCompiler, boolean: bool) {
|
||||||
let output = get_output(program);
|
let output = get_output(program);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
EdwardsConstrainedValue::Return(vec![ConstrainedValue::Boolean(Boolean::Constant(true))])
|
EdwardsConstrainedValue::Return(vec![ConstrainedValue::Boolean(Boolean::Constant(
|
||||||
|
boolean
|
||||||
|
))])
|
||||||
.to_string(),
|
.to_string(),
|
||||||
output.to_string()
|
output.to_string()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn output_true(program: EdwardsTestCompiler) {
|
||||||
|
output_expected_boolean(program, true)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn output_false(program: EdwardsTestCompiler) {
|
pub fn output_false(program: EdwardsTestCompiler) {
|
||||||
let output = get_output(program);
|
output_expected_boolean(program, false)
|
||||||
assert_eq!(
|
|
||||||
EdwardsConstrainedValue::Return(vec![ConstrainedValue::Boolean(Boolean::Constant(false))])
|
|
||||||
.to_string(),
|
|
||||||
output.to_string()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fail_evaluate(program: EdwardsTestCompiler) {
|
fn fail_evaluate(program: EdwardsTestCompiler) {
|
||||||
|
3
compiler/tests/field/add.leo
Normal file
3
compiler/tests/field/add.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main(a: field, b: field) -> field {
|
||||||
|
return a + b
|
||||||
|
}
|
3
compiler/tests/field/assert_eq.leo
Normal file
3
compiler/tests/field/assert_eq.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main(a: field, b: field) {
|
||||||
|
assert_eq!(a, b);
|
||||||
|
}
|
3
compiler/tests/field/div.leo
Normal file
3
compiler/tests/field/div.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main(a: field, b: field) -> field {
|
||||||
|
return a / b
|
||||||
|
}
|
3
compiler/tests/field/eq.leo
Normal file
3
compiler/tests/field/eq.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main(a: field, b: field) -> bool {
|
||||||
|
return a == b
|
||||||
|
}
|
3
compiler/tests/field/ge.leo
Normal file
3
compiler/tests/field/ge.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main(a: field, b: field) -> bool {
|
||||||
|
return a >= b
|
||||||
|
}
|
3
compiler/tests/field/gt.leo
Normal file
3
compiler/tests/field/gt.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main(a: field, b: field) -> bool {
|
||||||
|
return a > b
|
||||||
|
}
|
3
compiler/tests/field/le.leo
Normal file
3
compiler/tests/field/le.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main(a: field, b: field) -> bool {
|
||||||
|
return a <= b
|
||||||
|
}
|
3
compiler/tests/field/lt.leo
Normal file
3
compiler/tests/field/lt.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main(a: field, b: field) -> bool {
|
||||||
|
return a < b
|
||||||
|
}
|
438
compiler/tests/field/mod.rs
Normal file
438
compiler/tests/field/mod.rs
Normal file
@ -0,0 +1,438 @@
|
|||||||
|
use crate::boolean::{output_expected_boolean, output_false, output_true};
|
||||||
|
use crate::{compile_program, get_error, get_output, EdwardsConstrainedValue, EdwardsTestCompiler};
|
||||||
|
use leo_compiler::{
|
||||||
|
errors::{CompilerError, FieldError, FunctionError},
|
||||||
|
ConstrainedValue, FieldType, InputValue,
|
||||||
|
};
|
||||||
|
|
||||||
|
use snarkos_curves::edwards_bls12::Fq;
|
||||||
|
use snarkos_gadgets::curves::edwards_bls12::FqGadget;
|
||||||
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
|
use snarkos_models::gadgets::{
|
||||||
|
curves::field::FieldGadget,
|
||||||
|
r1cs::{ConstraintSystem, TestConstraintSystem},
|
||||||
|
};
|
||||||
|
use snarkos_utilities::biginteger::BigInteger256;
|
||||||
|
|
||||||
|
const DIRECTORY_NAME: &str = "tests/field/";
|
||||||
|
|
||||||
|
fn output_expected_constant(program: EdwardsTestCompiler, expected: Fq) {
|
||||||
|
let output = get_output(program);
|
||||||
|
assert_eq!(
|
||||||
|
EdwardsConstrainedValue::Return(vec![ConstrainedValue::Field(FieldType::Constant(
|
||||||
|
expected
|
||||||
|
))])
|
||||||
|
.to_string(),
|
||||||
|
output.to_string()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output_expected_allocated(program: EdwardsTestCompiler, expected: FqGadget) {
|
||||||
|
let output = get_output(program);
|
||||||
|
|
||||||
|
match output {
|
||||||
|
EdwardsConstrainedValue::Return(vec) => match vec.as_slice() {
|
||||||
|
[ConstrainedValue::Field(FieldType::Allocated(fp_gadget))] => {
|
||||||
|
assert_eq!(*fp_gadget, expected as FqGadget)
|
||||||
|
}
|
||||||
|
_ => panic!("program output unknown return value"),
|
||||||
|
},
|
||||||
|
_ => panic!("program output unknown return value"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output_zero(program: EdwardsTestCompiler) {
|
||||||
|
output_expected_constant(program, Fq::zero())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output_one(program: EdwardsTestCompiler) {
|
||||||
|
output_expected_constant(program, Fq::one())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fail_field(program: EdwardsTestCompiler) {
|
||||||
|
match get_error(program) {
|
||||||
|
CompilerError::FunctionError(FunctionError::FieldError(FieldError::Invalid(_string))) => {}
|
||||||
|
error => panic!("Expected invalid field error, got {}", error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fail_synthesis(program: EdwardsTestCompiler) {
|
||||||
|
match get_error(program) {
|
||||||
|
CompilerError::FunctionError(FunctionError::FieldError(FieldError::SynthesisError(
|
||||||
|
_string,
|
||||||
|
))) => {}
|
||||||
|
error => panic!("Expected synthesis error, got {}", error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_zero() {
|
||||||
|
let program = compile_program(DIRECTORY_NAME, "zero.leo").unwrap();
|
||||||
|
output_zero(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_one() {
|
||||||
|
let program = compile_program(DIRECTORY_NAME, "one.leo").unwrap();
|
||||||
|
output_one(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_pass() {
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "input.leo").unwrap();
|
||||||
|
program.set_inputs(vec![Some(InputValue::Field("1".into()))]);
|
||||||
|
|
||||||
|
let cs = TestConstraintSystem::<Fq>::new();
|
||||||
|
let expected = FqGadget::one(cs).unwrap();
|
||||||
|
|
||||||
|
output_expected_allocated(program, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_fail_bool() {
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "input.leo").unwrap();
|
||||||
|
program.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||||
|
fail_field(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_fail_none() {
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "input.leo").unwrap();
|
||||||
|
program.set_inputs(vec![None]);
|
||||||
|
fail_synthesis(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add() {
|
||||||
|
use std::ops::Add;
|
||||||
|
|
||||||
|
for _ in 0..10 {
|
||||||
|
let r1: u64 = rand::random();
|
||||||
|
let r2: u64 = rand::random();
|
||||||
|
|
||||||
|
let b1 = BigInteger256::from(r1);
|
||||||
|
let b2 = BigInteger256::from(r2);
|
||||||
|
|
||||||
|
let f1: Fq = Fq::from_repr(b1);
|
||||||
|
let f2: Fq = Fq::from_repr(b2);
|
||||||
|
|
||||||
|
let sum = f1.add(&f2);
|
||||||
|
|
||||||
|
let cs = TestConstraintSystem::<Fq>::new();
|
||||||
|
let sum_allocated = FqGadget::from(cs, &sum);
|
||||||
|
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "add.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r2.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_expected_allocated(program, sum_allocated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sub() {
|
||||||
|
use std::ops::Sub;
|
||||||
|
|
||||||
|
for _ in 0..10 {
|
||||||
|
let r1: u64 = rand::random();
|
||||||
|
let r2: u64 = rand::random();
|
||||||
|
|
||||||
|
let b1 = BigInteger256::from(r1);
|
||||||
|
let b2 = BigInteger256::from(r2);
|
||||||
|
|
||||||
|
let f1: Fq = Fq::from_repr(b1);
|
||||||
|
let f2: Fq = Fq::from_repr(b2);
|
||||||
|
|
||||||
|
let difference = f1.sub(&f2);
|
||||||
|
|
||||||
|
let cs = TestConstraintSystem::<Fq>::new();
|
||||||
|
let difference_allocated = FqGadget::from(cs, &difference);
|
||||||
|
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "sub.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r2.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_expected_allocated(program, difference_allocated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mul() {
|
||||||
|
use std::ops::Mul;
|
||||||
|
|
||||||
|
for _ in 0..10 {
|
||||||
|
let r1: u64 = rand::random();
|
||||||
|
let r2: u64 = rand::random();
|
||||||
|
|
||||||
|
let b1 = BigInteger256::from(r1);
|
||||||
|
let b2 = BigInteger256::from(r2);
|
||||||
|
|
||||||
|
let f1: Fq = Fq::from_repr(b1);
|
||||||
|
let f2: Fq = Fq::from_repr(b2);
|
||||||
|
|
||||||
|
let product = f1.mul(&f2);
|
||||||
|
|
||||||
|
let cs = TestConstraintSystem::<Fq>::new();
|
||||||
|
let product_allocated = FqGadget::from(cs, &product);
|
||||||
|
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "mul.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r2.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_expected_allocated(program, product_allocated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_div() {
|
||||||
|
use std::ops::Div;
|
||||||
|
|
||||||
|
for _ in 0..10 {
|
||||||
|
let r1: u64 = rand::random();
|
||||||
|
let r2: u64 = rand::random();
|
||||||
|
|
||||||
|
let b1 = BigInteger256::from(r1);
|
||||||
|
let b2 = BigInteger256::from(r2);
|
||||||
|
|
||||||
|
let f1: Fq = Fq::from_repr(b1);
|
||||||
|
let f2: Fq = Fq::from_repr(b2);
|
||||||
|
|
||||||
|
let quotient = f1.div(&f2);
|
||||||
|
|
||||||
|
let cs = TestConstraintSystem::<Fq>::new();
|
||||||
|
let quotient_allocated = FqGadget::from(cs, "ient);
|
||||||
|
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "div.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r2.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_expected_allocated(program, quotient_allocated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_eq() {
|
||||||
|
for _ in 0..10 {
|
||||||
|
let r1: u64 = rand::random();
|
||||||
|
|
||||||
|
// test equal
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "eq.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_true(program);
|
||||||
|
|
||||||
|
// test not equal
|
||||||
|
let r2: u64 = rand::random();
|
||||||
|
|
||||||
|
let result = r1.eq(&r2);
|
||||||
|
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "eq.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r2.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_expected_boolean(program, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ge() {
|
||||||
|
for _ in 0..10 {
|
||||||
|
let r1: u64 = rand::random();
|
||||||
|
|
||||||
|
// test equal
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "ge.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_true(program);
|
||||||
|
|
||||||
|
// test greater than
|
||||||
|
let r2: u64 = rand::random();
|
||||||
|
|
||||||
|
let result = r1.ge(&r2);
|
||||||
|
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "ge.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r2.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_expected_boolean(program, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_gt() {
|
||||||
|
for _ in 0..10 {
|
||||||
|
let r1: u64 = rand::random();
|
||||||
|
|
||||||
|
// test equal
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "gt.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_false(program);
|
||||||
|
|
||||||
|
// test greater than
|
||||||
|
let r2: u64 = rand::random();
|
||||||
|
|
||||||
|
let result = r1.gt(&r2);
|
||||||
|
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "gt.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r2.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_expected_boolean(program, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_le() {
|
||||||
|
for _ in 0..10 {
|
||||||
|
let r1: u64 = rand::random();
|
||||||
|
|
||||||
|
// test equal
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "le.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_true(program);
|
||||||
|
|
||||||
|
// test greater than
|
||||||
|
let r2: u64 = rand::random();
|
||||||
|
|
||||||
|
let result = r1.le(&r2);
|
||||||
|
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "le.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r2.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_expected_boolean(program, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lt() {
|
||||||
|
for _ in 0..10 {
|
||||||
|
let r1: u64 = rand::random();
|
||||||
|
|
||||||
|
// test equal
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "lt.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_false(program);
|
||||||
|
|
||||||
|
// test greater than
|
||||||
|
let r2: u64 = rand::random();
|
||||||
|
|
||||||
|
let result = r1.lt(&r2);
|
||||||
|
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "lt.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r2.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_expected_boolean(program, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_assert_eq_pass() {
|
||||||
|
for _ in 0..10 {
|
||||||
|
let r1: u64 = rand::random();
|
||||||
|
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "assert_eq.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let _ = get_output(program);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_assert_eq_fail() {
|
||||||
|
for _ in 0..10 {
|
||||||
|
let r1: u64 = rand::random();
|
||||||
|
let r2: u64 = rand::random();
|
||||||
|
|
||||||
|
if r1 == r2 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "assert_eq.leo").unwrap();
|
||||||
|
program.set_inputs(vec![
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r2.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let mut cs = TestConstraintSystem::<Fq>::new();
|
||||||
|
let _ = program.compile_constraints(&mut cs).unwrap();
|
||||||
|
assert!(!cs.is_satisfied());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ternary() {
|
||||||
|
let r1: u64 = rand::random();
|
||||||
|
let r2: u64 = rand::random();
|
||||||
|
|
||||||
|
let b1 = BigInteger256::from(r1);
|
||||||
|
let b2 = BigInteger256::from(r2);
|
||||||
|
|
||||||
|
let f1: Fq = Fq::from_repr(b1);
|
||||||
|
let f2: Fq = Fq::from_repr(b2);
|
||||||
|
|
||||||
|
let mut cs = TestConstraintSystem::<Fq>::new();
|
||||||
|
let g1 = FqGadget::from(cs.ns(|| "g1"), &f1);
|
||||||
|
let g2 = FqGadget::from(cs.ns(|| "g2"), &f2);
|
||||||
|
|
||||||
|
let mut program_1 = compile_program(DIRECTORY_NAME, "ternary.leo").unwrap();
|
||||||
|
let mut program_2 = program_1.clone();
|
||||||
|
|
||||||
|
// true -> field 1
|
||||||
|
program_1.set_inputs(vec![
|
||||||
|
Some(InputValue::Boolean(true)),
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r2.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_expected_allocated(program_1, g1);
|
||||||
|
|
||||||
|
// false -> field 2
|
||||||
|
program_2.set_inputs(vec![
|
||||||
|
Some(InputValue::Boolean(false)),
|
||||||
|
Some(InputValue::Field(r1.to_string())),
|
||||||
|
Some(InputValue::Field(r2.to_string())),
|
||||||
|
]);
|
||||||
|
|
||||||
|
output_expected_allocated(program_2, g2);
|
||||||
|
}
|
3
compiler/tests/field/mul.leo
Normal file
3
compiler/tests/field/mul.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main(a: field, b: field) -> field {
|
||||||
|
return a * b
|
||||||
|
}
|
3
compiler/tests/field/sub.leo
Normal file
3
compiler/tests/field/sub.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main(a: field, b: field) -> field {
|
||||||
|
return a - b
|
||||||
|
}
|
3
compiler/tests/field/ternary.leo
Normal file
3
compiler/tests/field/ternary.leo
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function main(b: bool, f1: field, f2: field) -> field {
|
||||||
|
return if b ? f1 : f2
|
||||||
|
}
|
@ -1,76 +0,0 @@
|
|||||||
use crate::{compile_program, get_error, get_output, EdwardsConstrainedValue, EdwardsTestCompiler};
|
|
||||||
use leo_compiler::{
|
|
||||||
errors::{CompilerError, FieldElementError, FunctionError},
|
|
||||||
ConstrainedValue, FieldElement, InputValue,
|
|
||||||
};
|
|
||||||
|
|
||||||
use snarkos_curves::edwards_bls12::Fq;
|
|
||||||
use snarkos_models::curves::Field;
|
|
||||||
|
|
||||||
const DIRECTORY_NAME: &str = "tests/field_element/";
|
|
||||||
|
|
||||||
fn output_zero(program: EdwardsTestCompiler) {
|
|
||||||
let output = get_output(program);
|
|
||||||
assert_eq!(
|
|
||||||
EdwardsConstrainedValue::Return(vec![ConstrainedValue::FieldElement(
|
|
||||||
FieldElement::Constant(Fq::zero())
|
|
||||||
)])
|
|
||||||
.to_string(),
|
|
||||||
output.to_string()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_one(program: EdwardsTestCompiler) {
|
|
||||||
let output = get_output(program);
|
|
||||||
assert_eq!(
|
|
||||||
EdwardsConstrainedValue::Return(vec![ConstrainedValue::FieldElement(
|
|
||||||
FieldElement::Constant(Fq::one())
|
|
||||||
)])
|
|
||||||
.to_string(),
|
|
||||||
output.to_string()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fail_field(program: EdwardsTestCompiler) {
|
|
||||||
match get_error(program) {
|
|
||||||
CompilerError::FunctionError(FunctionError::FieldElementError(
|
|
||||||
FieldElementError::InvalidField(_string),
|
|
||||||
)) => {}
|
|
||||||
error => panic!("Expected invalid field error, got {}", error),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fail_synthesis(program: EdwardsTestCompiler) {
|
|
||||||
match get_error(program) {
|
|
||||||
CompilerError::FunctionError(FunctionError::FieldElementError(
|
|
||||||
FieldElementError::SynthesisError(_string),
|
|
||||||
)) => {}
|
|
||||||
error => panic!("Expected synthesis error, got {}", error),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_zero() {
|
|
||||||
let program = compile_program(DIRECTORY_NAME, "zero.leo").unwrap();
|
|
||||||
output_zero(program);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_one() {
|
|
||||||
let program = compile_program(DIRECTORY_NAME, "one.leo").unwrap();
|
|
||||||
output_one(program);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_input_field_bool() {
|
|
||||||
let mut program = compile_program(DIRECTORY_NAME, "input_field.leo").unwrap();
|
|
||||||
program.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
|
||||||
fail_field(program);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_input_field_none() {
|
|
||||||
let mut program = compile_program(DIRECTORY_NAME, "input_field.leo").unwrap();
|
|
||||||
program.set_inputs(vec![None]);
|
|
||||||
fail_synthesis(program);
|
|
||||||
}
|
|
@ -1,18 +1,14 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
boolean::{output_false, output_true},
|
boolean::{output_false, output_true},
|
||||||
compile_program, get_error, get_output, EdwardsConstrainedValue, EdwardsTestCompiler,
|
compile_program, fail_enforce, get_output, EdwardsConstrainedValue, EdwardsTestCompiler,
|
||||||
};
|
|
||||||
use leo_compiler::{
|
|
||||||
errors::{CompilerError, FunctionError, StatementError},
|
|
||||||
group::edwards_bls12::EdwardsGroupType,
|
|
||||||
ConstrainedValue, InputValue,
|
|
||||||
};
|
};
|
||||||
|
use leo_compiler::{group::edwards_bls12::EdwardsGroupType, ConstrainedValue, InputValue};
|
||||||
|
|
||||||
use snarkos_curves::edwards_bls12::{EdwardsAffine, Fq};
|
use snarkos_curves::edwards_bls12::{EdwardsAffine, Fq};
|
||||||
use snarkos_gadgets::curves::edwards_bls12::EdwardsBlsGadget;
|
use snarkos_gadgets::curves::edwards_bls12::EdwardsBlsGadget;
|
||||||
use snarkos_models::{
|
use snarkos_models::{
|
||||||
curves::Group,
|
curves::Group,
|
||||||
gadgets::{curves::GroupGadget, r1cs::TestConstraintSystem, utilities::alloc::AllocGadget},
|
gadgets::{r1cs::TestConstraintSystem, utilities::alloc::AllocGadget},
|
||||||
};
|
};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
@ -34,28 +30,22 @@ fn output_expected_constant(program: EdwardsTestCompiler, expected: EdwardsAffin
|
|||||||
|
|
||||||
fn output_expected_allocated(program: EdwardsTestCompiler, expected: EdwardsBlsGadget) {
|
fn output_expected_allocated(program: EdwardsTestCompiler, expected: EdwardsBlsGadget) {
|
||||||
let output = get_output(program);
|
let output = get_output(program);
|
||||||
assert_eq!(
|
|
||||||
EdwardsConstrainedValue::Return(vec![ConstrainedValue::Group(
|
match output {
|
||||||
EdwardsGroupType::Allocated(expected)
|
EdwardsConstrainedValue::Return(vec) => match vec.as_slice() {
|
||||||
)])
|
[ConstrainedValue::Group(EdwardsGroupType::Allocated(gadget))] => {
|
||||||
.to_string(),
|
assert_eq!(*gadget, expected as EdwardsBlsGadget)
|
||||||
output.to_string()
|
}
|
||||||
)
|
_ => panic!("program output unknown return value"),
|
||||||
|
},
|
||||||
|
_ => panic!("program output unknown return value"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output_zero(program: EdwardsTestCompiler) {
|
fn output_zero(program: EdwardsTestCompiler) {
|
||||||
output_expected_constant(program, EdwardsAffine::zero())
|
output_expected_constant(program, EdwardsAffine::zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fail_enforce(program: EdwardsTestCompiler) {
|
|
||||||
match get_error(program) {
|
|
||||||
CompilerError::FunctionError(FunctionError::StatementError(
|
|
||||||
StatementError::SynthesisError(_),
|
|
||||||
)) => {}
|
|
||||||
error => panic!("Expected evaluate error, got {}", error),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_zero() {
|
fn test_zero() {
|
||||||
let program = compile_program(DIRECTORY_NAME, "zero.leo").unwrap();
|
let program = compile_program(DIRECTORY_NAME, "zero.leo").unwrap();
|
||||||
@ -69,6 +59,20 @@ fn test_point() {
|
|||||||
output_expected_constant(program, point);
|
output_expected_constant(program, point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input() {
|
||||||
|
let mut program = compile_program(DIRECTORY_NAME, "input.leo").unwrap();
|
||||||
|
program.set_inputs(vec![Some(InputValue::Group(TEST_POINT_1.into()))]);
|
||||||
|
|
||||||
|
let mut cs = TestConstraintSystem::<Fq>::new();
|
||||||
|
let constant_point = EdwardsAffine::from_str(TEST_POINT_1).unwrap();
|
||||||
|
let allocated_point =
|
||||||
|
<EdwardsBlsGadget as AllocGadget<EdwardsAffine, Fq>>::alloc(&mut cs, || Ok(constant_point))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
output_expected_allocated(program, allocated_point);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add() {
|
fn test_add() {
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
@ -108,31 +112,17 @@ fn test_eq_false() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_assert_eq_true() {
|
fn test_assert_eq_pass() {
|
||||||
let program = compile_program(DIRECTORY_NAME, "assert_eq_true.leo").unwrap();
|
let program = compile_program(DIRECTORY_NAME, "assert_eq_true.leo").unwrap();
|
||||||
let _res = get_output(program);
|
let _res = get_output(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_assert_eq_false() {
|
fn test_assert_eq_fail() {
|
||||||
let program = compile_program(DIRECTORY_NAME, "assert_eq_false.leo").unwrap();
|
let program = compile_program(DIRECTORY_NAME, "assert_eq_false.leo").unwrap();
|
||||||
fail_enforce(program);
|
fail_enforce(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_input() {
|
|
||||||
let mut program = compile_program(DIRECTORY_NAME, "input.leo").unwrap();
|
|
||||||
program.set_inputs(vec![Some(InputValue::Group(TEST_POINT_1.into()))]);
|
|
||||||
|
|
||||||
let mut cs = TestConstraintSystem::<Fq>::new();
|
|
||||||
let constant_point = EdwardsAffine::from_str(TEST_POINT_1).unwrap();
|
|
||||||
let allocated_point =
|
|
||||||
<EdwardsBlsGadget as AllocGadget<EdwardsAffine, Fq>>::alloc(&mut cs, || Ok(constant_point))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
output_expected_allocated(program, allocated_point);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ternary() {
|
fn test_ternary() {
|
||||||
let mut program_1 = compile_program(DIRECTORY_NAME, "ternary.leo").unwrap();
|
let mut program_1 = compile_program(DIRECTORY_NAME, "ternary.leo").unwrap();
|
||||||
@ -141,36 +131,20 @@ fn test_ternary() {
|
|||||||
// true -> point_1
|
// true -> point_1
|
||||||
program_1.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
program_1.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||||
|
|
||||||
|
let mut cs = TestConstraintSystem::<Fq>::new();
|
||||||
let point_1 = EdwardsAffine::from_str(TEST_POINT_1).unwrap();
|
let point_1 = EdwardsAffine::from_str(TEST_POINT_1).unwrap();
|
||||||
let output_1 = get_output(program_1);
|
let expected_point_1 =
|
||||||
let actual_1: EdwardsAffine = match output_1 {
|
<EdwardsBlsGadget as AllocGadget<EdwardsAffine, Fq>>::alloc(&mut cs, || Ok(point_1))
|
||||||
EdwardsConstrainedValue::Return(vec) => match vec.as_slice() {
|
.unwrap();
|
||||||
[ConstrainedValue::Group(EdwardsGroupType::Allocated(edwards_gadget))] => {
|
output_expected_allocated(program_1, expected_point_1);
|
||||||
<EdwardsBlsGadget as GroupGadget<EdwardsAffine, Fq>>::get_value(edwards_gadget)
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
_ => panic!("program output unknown return value"),
|
|
||||||
},
|
|
||||||
_ => panic!("program output unknown return value"),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(point_1, actual_1);
|
|
||||||
|
|
||||||
// false -> point_2
|
// false -> point_2
|
||||||
program_2.set_inputs(vec![Some(InputValue::Boolean(false))]);
|
program_2.set_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||||
|
|
||||||
|
let mut cs = TestConstraintSystem::<Fq>::new();
|
||||||
let point_2 = EdwardsAffine::from_str(TEST_POINT_2).unwrap();
|
let point_2 = EdwardsAffine::from_str(TEST_POINT_2).unwrap();
|
||||||
let output_2 = get_output(program_2);
|
let expected_point_2 =
|
||||||
let actual_2: EdwardsAffine = match output_2 {
|
<EdwardsBlsGadget as AllocGadget<EdwardsAffine, Fq>>::alloc(&mut cs, || Ok(point_2))
|
||||||
EdwardsConstrainedValue::Return(vec) => match vec.as_slice() {
|
.unwrap();
|
||||||
[ConstrainedValue::Group(EdwardsGroupType::Allocated(edwards_gadget))] => {
|
output_expected_allocated(program_2, expected_point_2);
|
||||||
<EdwardsBlsGadget as GroupGadget<EdwardsAffine, Fq>>::get_value(edwards_gadget)
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
_ => panic!("program output unknown return value"),
|
|
||||||
},
|
|
||||||
_ => panic!("program output unknown return value"),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(point_2, actual_2);
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
pub mod array;
|
pub mod array;
|
||||||
pub mod boolean;
|
pub mod boolean;
|
||||||
pub mod circuit;
|
pub mod circuit;
|
||||||
pub mod field_element;
|
pub mod field;
|
||||||
pub mod function;
|
pub mod function;
|
||||||
pub mod group;
|
pub mod group;
|
||||||
pub mod import;
|
pub mod import;
|
||||||
@ -10,7 +10,9 @@ pub mod mutability;
|
|||||||
pub mod statement;
|
pub mod statement;
|
||||||
|
|
||||||
use leo_compiler::{
|
use leo_compiler::{
|
||||||
compiler::Compiler, errors::CompilerError, group::edwards_bls12::EdwardsGroupType,
|
compiler::Compiler,
|
||||||
|
errors::{CompilerError, FunctionError, StatementError},
|
||||||
|
group::edwards_bls12::EdwardsGroupType,
|
||||||
ConstrainedValue,
|
ConstrainedValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -33,6 +35,15 @@ pub(crate) fn get_error(program: EdwardsTestCompiler) -> CompilerError {
|
|||||||
program.compile_constraints(&mut cs).unwrap_err()
|
program.compile_constraints(&mut cs).unwrap_err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn fail_enforce(program: EdwardsTestCompiler) {
|
||||||
|
match get_error(program) {
|
||||||
|
CompilerError::FunctionError(FunctionError::StatementError(
|
||||||
|
StatementError::SynthesisError(_),
|
||||||
|
)) => {}
|
||||||
|
error => panic!("Expected evaluate error, got {}", error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn compile_program(
|
pub(crate) fn compile_program(
|
||||||
directory_name: &str,
|
directory_name: &str,
|
||||||
file_name: &str,
|
file_name: &str,
|
||||||
|
@ -2,16 +2,10 @@ use crate::directories::{source::SOURCE_DIRECTORY_NAME, OutputsDirectory};
|
|||||||
use crate::errors::{BuildError, CLIError};
|
use crate::errors::{BuildError, CLIError};
|
||||||
use crate::files::{ChecksumFile, MainFile, Manifest, MAIN_FILE_NAME};
|
use crate::files::{ChecksumFile, MainFile, Manifest, MAIN_FILE_NAME};
|
||||||
use crate::{cli::*, cli_types::*};
|
use crate::{cli::*, cli_types::*};
|
||||||
use leo_compiler::{
|
use leo_compiler::{compiler::Compiler, group::edwards_bls12::EdwardsGroupType};
|
||||||
compiler::Compiler,
|
|
||||||
group::edwards_bls12::EdwardsGroupType
|
|
||||||
};
|
|
||||||
|
|
||||||
use snarkos_algorithms::snark::KeypairAssembly;
|
use snarkos_algorithms::snark::KeypairAssembly;
|
||||||
use snarkos_curves::{
|
use snarkos_curves::{bls12_377::Bls12_377, edwards_bls12::Fq};
|
||||||
bls12_377::Bls12_377,
|
|
||||||
edwards_bls12::Fq
|
|
||||||
};
|
|
||||||
|
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
@ -2,18 +2,12 @@ use crate::commands::BuildCommand;
|
|||||||
use crate::errors::{CLIError, VerificationKeyFileError};
|
use crate::errors::{CLIError, VerificationKeyFileError};
|
||||||
use crate::files::{Manifest, ProvingKeyFile, VerificationKeyFile};
|
use crate::files::{Manifest, ProvingKeyFile, VerificationKeyFile};
|
||||||
use crate::{cli::*, cli_types::*};
|
use crate::{cli::*, cli_types::*};
|
||||||
use leo_compiler::{
|
use leo_compiler::{compiler::Compiler, group::edwards_bls12::EdwardsGroupType};
|
||||||
compiler::Compiler,
|
|
||||||
group::edwards_bls12::EdwardsGroupType
|
|
||||||
};
|
|
||||||
|
|
||||||
use snarkos_algorithms::snark::{
|
use snarkos_algorithms::snark::{
|
||||||
generate_random_parameters, prepare_verifying_key, Parameters, PreparedVerifyingKey,
|
generate_random_parameters, prepare_verifying_key, Parameters, PreparedVerifyingKey,
|
||||||
};
|
};
|
||||||
use snarkos_curves::{
|
use snarkos_curves::{bls12_377::Bls12_377, edwards_bls12::Fq};
|
||||||
bls12_377::Bls12_377,
|
|
||||||
edwards_bls12::Fq
|
|
||||||
};
|
|
||||||
use snarkos_utilities::bytes::ToBytes;
|
use snarkos_utilities::bytes::ToBytes;
|
||||||
|
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
|
Loading…
Reference in New Issue
Block a user