Merge pull request #43 from AleoHQ/feature/test-syntax-new

Feature/test syntax new
This commit is contained in:
Collin Chin 2020-06-05 19:02:35 -07:00 committed by GitHub
commit e985027e86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
113 changed files with 1146 additions and 96 deletions

View File

@ -1225,6 +1225,16 @@ pub struct Import<'ast> {
pub span: Span<'ast>,
}
// Tests
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::test))]
pub struct Test<'ast> {
pub function: Function<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
// File
#[derive(Clone, Debug, FromPest, PartialEq)]
@ -1233,6 +1243,7 @@ pub struct File<'ast> {
pub imports: Vec<Import<'ast>>,
pub circuits: Vec<Circuit<'ast>>,
pub functions: Vec<Function<'ast>>,
pub tests: Vec<Test<'ast>>,
pub eoi: EOI,
#[pest_ast(outer())]
pub span: Span<'ast>,

View File

@ -2,7 +2,7 @@
use crate::{
ast,
constraints::{generate_constraints, ConstrainedValue},
constraints::{generate_constraints, generate_test_constraints, ConstrainedValue},
errors::CompilerError,
GroupType, InputValue, Program,
};
@ -10,7 +10,7 @@ use crate::{
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::{ConstraintSynthesizer, ConstraintSystem},
gadgets::r1cs::{ConstraintSynthesizer, ConstraintSystem, TestConstraintSystem},
};
use from_pest::FromPest;
@ -68,6 +68,13 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
generate_constraints(cs, self.program, self.program_inputs)
}
pub fn compile_test_constraints(
self,
cs: &mut TestConstraintSystem<F>,
) -> Result<(), CompilerError> {
generate_test_constraints::<F, G>(cs, self.program)
}
// pub fn compile(&self) -> Result<ast::File, CompilerError> {
// // Read in the main file as string
// let unparsed_file = fs::read_to_string(&self.main_file_path).map_err(|_| CompilerError::FileReadError(self.main_file_path.clone()))?;

View File

@ -236,6 +236,10 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
right: ConstrainedValue<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
let result = num_1.ge(&num_2);
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
}
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
let result = fe_1.ge(&fe_2);
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
@ -261,6 +265,10 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
right: ConstrainedValue<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
let result = num_1.gt(&num_2);
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
}
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
let result = fe_1.gt(&fe_2);
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
@ -286,6 +294,10 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
right: ConstrainedValue<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
let result = num_1.le(&num_2);
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
}
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
let result = fe_1.le(&fe_2);
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
@ -311,6 +323,10 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
right: ConstrainedValue<F, G>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match (left, right) {
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
let result = num_1.lt(&num_2);
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))
}
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
let result = fe_1.lt(&fe_2);
Ok(ConstrainedValue::Boolean(Boolean::Constant(result)))

View File

@ -366,7 +366,7 @@ impl Integer {
let result = left_u8.div(
cs.ns(|| {
format!(
"enforce {} / {}",
"enforce {} ÷ {}",
left_u8.value.unwrap(),
right_u8.value.unwrap()
)
@ -379,7 +379,7 @@ impl Integer {
let result = left_u16.div(
cs.ns(|| {
format!(
"enforce {} / {}",
"enforce {} ÷ {}",
left_u16.value.unwrap(),
right_u16.value.unwrap()
)
@ -392,7 +392,7 @@ impl Integer {
let result = left_u32.div(
cs.ns(|| {
format!(
"enforce {} / {}",
"enforce {} ÷ {}",
left_u32.value.unwrap(),
right_u32.value.unwrap()
)
@ -405,7 +405,7 @@ impl Integer {
let result = left_u64.div(
cs.ns(|| {
format!(
"enforce {} / {}",
"enforce {} ÷ {}",
left_u64.value.unwrap(),
right_u64.value.unwrap()
)
@ -418,7 +418,7 @@ impl Integer {
let result = left_u128.div(
cs.ns(|| {
format!(
"enforce {} / {}",
"enforce {} ÷ {}",
left_u128.value.unwrap(),
right_u128.value.unwrap()
)
@ -428,7 +428,7 @@ impl Integer {
Integer::U128(result)
}
(left, right) => {
return Err(IntegerError::CannotEnforce(format!("{} / {}", left, right)))
return Err(IntegerError::CannotEnforce(format!("{} ÷ {}", left, right)))
}
})
}

View File

@ -38,7 +38,7 @@ use crate::{
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
gadgets::r1cs::{ConstraintSystem, TestConstraintSystem},
};
pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
@ -66,3 +66,40 @@ pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
_ => Err(CompilerError::NoMainFunction),
}
}
pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
cs: &mut TestConstraintSystem<F>,
program: Program,
) -> Result<(), CompilerError> {
let mut resolved_program = ConstrainedProgram::<F, G, TestConstraintSystem<F>>::new();
let program_name = program.get_name();
let tests = program.tests.clone();
resolved_program.resolve_definitions(cs, program)?;
log::info!("Running {} tests", tests.len());
for (test_name, test_function) in tests.into_iter() {
let full_test_name = format!("{}::{}", program_name.clone(), test_name.to_string());
let result = resolved_program.enforce_main_function(
cs,
program_name.clone(),
test_function.0,
vec![], // test functions should not take any inputs
);
if result.is_ok() {
log::info!(
"test {} passed. Constraint system satisfied: {}",
full_test_name,
cs.is_satisfied()
);
} else {
log::error!("test {} errored: {}", full_test_name, result.unwrap_err());
}
}
Ok(())
}

View File

@ -414,14 +414,16 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
self.enforce_boolean_eq(cs, bool_1, bool_2)?
}
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
num_1.enforce_equal(cs, &num_2)?
}
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => {
fe_1.enforce_equal(cs, &fe_2)?
}
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => {
ge_1.enforce_equal(cs, &ge_2)?
num_1.enforce_equal(cs, &num_2).map_err(|_| {
StatementError::AssertionFailed(num_1.to_string(), num_2.to_string())
})?
}
(ConstrainedValue::Field(fe_1), ConstrainedValue::Field(fe_2)) => fe_1
.enforce_equal(cs, &fe_2)
.map_err(|_| StatementError::AssertionFailed(fe_1.to_string(), fe_2.to_string()))?,
(ConstrainedValue::Group(ge_1), ConstrainedValue::Group(ge_2)) => ge_1
.enforce_equal(cs, &ge_2)
.map_err(|_| StatementError::AssertionFailed(ge_1.to_string(), ge_2.to_string()))?,
(ConstrainedValue::Array(arr_1), ConstrainedValue::Array(arr_2)) => {
for (left, right) in arr_1.into_iter().zip(arr_2.into_iter()) {
self.enforce_assert_eq_statement(cs, left, right)?;

View File

@ -34,6 +34,9 @@ pub enum StatementError {
#[error("Cannot assert equality between {} == {}", _0, _1)]
AssertEq(String, String),
#[error("Assertion {:?} == {:?} failed", _0, _1)]
AssertionFailed(String, String),
#[error("If, else conditional must resolve to a boolean, got {}", _0)]
IfElseConditional(String),

View File

@ -287,3 +287,9 @@ impl<F: Field + PrimeField> ToBytesGadget<F> for FieldType<F> {
self_gadget.to_bytes_strict(cs)
}
}
impl<F: Field + PrimeField> std::fmt::Display for FieldType<F> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self.get_value().ok_or(std::fmt::Error))
}
}

View File

@ -304,3 +304,12 @@ impl ToBytesGadget<Fq> for EdwardsGroupType {
self_gadget.to_bytes_strict(cs)
}
}
impl std::fmt::Display for EdwardsGroupType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
EdwardsGroupType::Constant(constant) => write!(f, "{:?}", constant),
EdwardsGroupType::Allocated(allocated) => write!(f, "{:?}", allocated),
}
}
}

View File

@ -14,7 +14,7 @@ use snarkos_models::{
},
},
};
use std::fmt::Debug;
use std::fmt::{Debug, Display};
pub mod edwards_bls12;
@ -22,6 +22,7 @@ pub trait GroupType<F: Field>:
Sized
+ Clone
+ Debug
+ Display
+ EqGadget<F>
+ ConditionalEqGadget<F>
+ AllocGadget<String, F>

View File

@ -226,6 +226,10 @@ import_symbol_tuple = _{ import_symbol ~ ("," ~ NEWLINE* ~ import_symbol)* }
import = { "from" ~ "\"" ~ import_source ~ "\"" ~ "import" ~ ("*" | ("{" ~ NEWLINE* ~ import_symbol_tuple ~ NEWLINE* ~ "}") | import_symbol) ~ LINE_END}
/// Tests
test = {"test" ~ function_definition}
/// Program File
file = { SOI ~ NEWLINE* ~ import* ~ NEWLINE* ~ circuit_definition* ~ NEWLINE* ~ function_definition* ~ NEWLINE* ~ EOI }
file = { SOI ~ NEWLINE* ~ import* ~ NEWLINE* ~ circuit_definition* ~ NEWLINE* ~ function_definition* ~ NEWLINE* ~ test* ~ NEWLINE* ~ EOI }

View File

@ -34,7 +34,7 @@ pub struct Variable {
}
/// An integer type enum wrapping the integer value. Used only in expressions.
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
pub enum Integer {
U8(UInt8),
U16(UInt16),
@ -219,7 +219,7 @@ pub struct InputModel {
#[derive(Clone, PartialEq, Eq)]
pub enum InputValue {
Integer(usize),
Integer(u128),
Field(String),
Group(String),
Boolean(bool),
@ -240,6 +240,11 @@ impl Function {
}
}
/// Tests
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Test(pub Function);
/// A simple program with statement expressions, program arguments and program returns.
#[derive(Debug, Clone)]
pub struct Program {
@ -248,6 +253,7 @@ pub struct Program {
pub imports: Vec<Import>,
pub circuits: HashMap<Identifier, Circuit>,
pub functions: HashMap<Identifier, Function>,
pub tests: HashMap<Identifier, Test>,
}
impl<'ast> Program {
@ -258,6 +264,7 @@ impl<'ast> Program {
imports: vec![],
circuits: HashMap::new(),
functions: HashMap::new(),
tests: HashMap::new(),
}
}

View File

@ -788,6 +788,13 @@ impl<'ast> From<ast::Import<'ast>> for Import {
}
}
/// pest ast -> Test
impl<'ast> From<ast::Test<'ast>> for types::Test {
fn from(test: ast::Test) -> Self {
types::Test(types::Function::from(test.function))
}
}
/// pest ast -> types::Program
impl<'ast> types::Program {
@ -801,6 +808,7 @@ impl<'ast> types::Program {
let mut circuits = HashMap::new();
let mut functions = HashMap::new();
let mut tests = HashMap::new();
let mut num_parameters = 0usize;
file.circuits.into_iter().for_each(|circuit| {
@ -815,6 +823,12 @@ impl<'ast> types::Program {
types::Function::from(function_def),
);
});
file.tests.into_iter().for_each(|test_def| {
tests.insert(
types::Identifier::from(test_def.function.function_name.clone()),
types::Test::from(test_def),
);
});
if let Some(main_function) = functions.get(&types::Identifier::new("main".into())) {
num_parameters = main_function.inputs.len();
@ -826,6 +840,7 @@ impl<'ast> types::Program {
imports,
circuits,
functions,
tests,
}
}
}

View File

@ -91,7 +91,7 @@ fn test_input_array() {
let mut program = compile_program(DIRECTORY_NAME, "input_array.leo").unwrap();
program.set_inputs(vec![Some(InputValue::Array(vec![
InputValue::Integer(
1usize
1u128
);
3
]))]);
@ -101,7 +101,7 @@ fn test_input_array() {
#[test]
fn test_input_array_fail() {
let mut program = compile_program(DIRECTORY_NAME, "input_array.leo").unwrap();
program.set_inputs(vec![Some(InputValue::Integer(1usize))]);
program.set_inputs(vec![Some(InputValue::Integer(1u128))]);
fail_array(program);
}

View File

@ -82,7 +82,7 @@ fn test_false() {
#[test]
fn test_input_bool_field() {
let mut program = compile_program(DIRECTORY_NAME, "input_bool.leo").unwrap();
program.set_inputs(vec![Some(InputValue::Integer(1usize))]);
program.set_inputs(vec![Some(InputValue::Integer(1u128))]);
fail_boolean(program);
}

View File

@ -0,0 +1,348 @@
macro_rules! test_uint {
($name: ident, $_type: ty, $gadget: ty, $directory: expr) => {
pub struct $name {}
impl $name {
fn test_min(min: $_type) {
let min_allocated = <$gadget>::constant(min);
let program = compile_program($directory, "min.leo").unwrap();
output_expected_allocated(program, min_allocated);
}
fn test_max(max: $_type) {
let max_allocated = <$gadget>::constant(max);
let program = compile_program($directory, "max.leo").unwrap();
output_expected_allocated(program, max_allocated);
}
}
impl IntegerTester for $name {
fn test_input() {
// valid input
let num: $_type = rand::random();
let expected = <$gadget>::constant(num);
let mut program = compile_program($directory, "input.leo").unwrap();
program.set_inputs(vec![Some(InputValue::Integer(num as u128))]);
output_expected_allocated(program, expected);
// invalid input
let mut program = compile_program($directory, "input.leo").unwrap();
program.set_inputs(vec![Some(InputValue::Boolean(true))]);
fail_integer(program);
// None input
let mut program = compile_program($directory, "input.leo").unwrap();
program.set_inputs(vec![None]);
fail_synthesis(program);
}
fn test_add() {
for _ in 0..10 {
let r1: $_type = rand::random();
let r2: $_type = rand::random();
let sum = r1.wrapping_add(r2);
let cs = TestConstraintSystem::<Fq>::new();
let sum_allocated = <$gadget>::alloc(cs, || Ok(sum)).unwrap();
let mut program = compile_program($directory, "add.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
]);
output_expected_allocated(program, sum_allocated);
}
}
fn test_sub() {
for _ in 0..10 {
let r1: $_type = rand::random();
let r2: $_type = rand::random();
let difference = r1.wrapping_sub(r2);
let cs = TestConstraintSystem::<Fq>::new();
let difference_allocated = <$gadget>::alloc(cs, || Ok(difference)).unwrap();
let mut program = compile_program($directory, "sub.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
]);
output_expected_allocated(program, difference_allocated);
}
}
fn test_mul() {
for _ in 0..10 {
let r1: $_type = rand::random();
let r2: $_type = rand::random();
let product = r1.wrapping_mul(r2);
let cs = TestConstraintSystem::<Fq>::new();
let product_allocated = <$gadget>::alloc(cs, || Ok(product)).unwrap();
let mut program = compile_program($directory, "mul.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
]);
output_expected_allocated(program, product_allocated);
}
}
fn test_div() {
for _ in 0..10 {
let r1: $_type = rand::random();
let r2: $_type = rand::random();
let quotient = r1.wrapping_div(r2);
let cs = TestConstraintSystem::<Fq>::new();
let quotient_allocated = <$gadget>::alloc(cs, || Ok(quotient)).unwrap();
let mut program = compile_program($directory, "div.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
]);
output_expected_allocated(program, quotient_allocated);
}
}
fn test_pow() {
// for _ in 0..10 {// these loops take an excessive amount of time
let r1: $_type = rand::random();
let r2: $_type = rand::random();
let r2 = r2 as u32; // we cast to u32 here because of rust pow() requirements
let result = r1.wrapping_pow(r2);
let cs = TestConstraintSystem::<Fq>::new();
let result_allocated = <$gadget>::alloc(cs, || Ok(result)).unwrap();
let mut program = compile_program($directory, "pow.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
]);
output_expected_allocated(program, result_allocated);
// }
}
fn test_eq() {
for _ in 0..10 {
let r1: $_type = rand::random();
// test equal
let mut program = compile_program($directory, "eq.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r1 as u128)),
]);
output_true(program);
// test not equal
let r2: $_type = rand::random();
let result = r1.eq(&r2);
let mut program = compile_program($directory, "eq.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
]);
output_expected_boolean(program, result);
}
}
fn test_ge() {
for _ in 0..10 {
let r1: $_type = rand::random();
// test equal
let mut program = compile_program($directory, "ge.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r1 as u128)),
]);
output_true(program);
// test not equal
let r2: $_type = rand::random();
let result = r1.ge(&r2);
let mut program = compile_program($directory, "ge.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
]);
output_expected_boolean(program, result);
}
}
fn test_gt() {
for _ in 0..10 {
let r1: $_type = rand::random();
// test equal
let mut program = compile_program($directory, "gt.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r1 as u128)),
]);
output_false(program);
// test not equal
let r2: $_type = rand::random();
let result = r1.gt(&r2);
let mut program = compile_program($directory, "gt.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
]);
output_expected_boolean(program, result);
}
}
fn test_le() {
for _ in 0..10 {
let r1: $_type = rand::random();
// test equal
let mut program = compile_program($directory, "le.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r1 as u128)),
]);
output_true(program);
// test not equal
let r2: $_type = rand::random();
let result = r1.le(&r2);
let mut program = compile_program($directory, "le.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
]);
output_expected_boolean(program, result);
}
}
fn test_lt() {
for _ in 0..10 {
let r1: $_type = rand::random();
// test equal
let mut program = compile_program($directory, "lt.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r1 as u128)),
]);
output_false(program);
// test not equal
let r2: $_type = rand::random();
let result = r1.lt(&r2);
let mut program = compile_program($directory, "lt.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
]);
output_expected_boolean(program, result);
}
}
fn test_assert_eq() {
for _ in 0..10 {
let r1: $_type = rand::random();
// test equal
let mut program = compile_program($directory, "assert_eq.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r1 as u128)),
]);
let _ = get_output(program);
// test not equal
let r2: $_type = rand::random();
if r1 == r2 {
continue;
}
let mut program = compile_program($directory, "assert_eq.leo").unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
]);
let mut cs = TestConstraintSystem::<Fq>::new();
let _ = program.compile_constraints(&mut cs).unwrap();
assert!(!cs.is_satisfied());
}
}
fn test_ternary() {
let r1: $_type = rand::random();
let r2: $_type = rand::random();
let g1 = <$gadget>::constant(r1);
let g2 = <$gadget>::constant(r2);
let mut program_1 = compile_program($directory, "ternary.leo").unwrap();
let mut program_2 = program_1.clone();
// true -> field 1
program_1.set_inputs(vec![
Some(InputValue::Boolean(true)),
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
]);
output_expected_allocated(program_1, g1);
// false -> field 2
program_2.set_inputs(vec![
Some(InputValue::Boolean(false)),
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
]);
output_expected_allocated(program_2, g2);
}
}
};
}

View File

@ -1 +1,71 @@
#[macro_use]
pub mod macros;
use crate::{get_error, EdwardsTestCompiler};
use leo_compiler::errors::{CompilerError, FunctionError, IntegerError};
pub trait IntegerTester {
/// Tests use of the integer in a function input
fn test_input();
/// Tests a wrapping addition
fn test_add();
/// Tests a wrapping subtraction
fn test_sub();
/// Tests a wrapping multiplication
fn test_mul();
/// Tests a non-wrapping division
fn test_div();
/// Tests a wrapping exponentiation
fn test_pow();
/// Tests == evaluation
fn test_eq();
/// Tests >= evaluation
fn test_ge();
/// Tests > evaluation
fn test_gt();
/// Tests <= evaluation
fn test_le();
/// Tests < evaluation
fn test_lt();
/// Test assert equals constraint keyword
fn test_assert_eq();
/// Test ternary if bool ? num_1 : num_2;
fn test_ternary();
}
pub(crate) fn fail_integer(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::IntegerError(
IntegerError::InvalidInteger(_string),
)) => {}
error => panic!("Expected invalid boolean error, got {}", error),
}
}
pub(crate) fn fail_synthesis(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::IntegerError(
IntegerError::SynthesisError(_string),
)) => {}
error => panic!("Expected synthesis error, got {}", error),
}
}
// must be below macro definitions!
pub mod u128;
pub mod u16;
pub mod u32;
pub mod u64;
pub mod u8;

View File

@ -0,0 +1,3 @@
function main(a: u128, b: u128) -> u128 {
return a + b
}

View File

@ -0,0 +1,3 @@
function main(a: u128, b: u128) {
assert_eq!(a, b);
}

View File

@ -0,0 +1,3 @@
function main(a: u128, b: u128) -> u128 {
return a / b
}

View File

@ -0,0 +1,3 @@
function main(a: u128, b: u128) -> bool {
return a == b
}

View File

@ -0,0 +1,3 @@
function main(a: u128, b: u128) -> bool {
return a >= b
}

View File

@ -0,0 +1,3 @@
function main(a: u128, b: u128) -> bool {
return a > b
}

View File

@ -0,0 +1,3 @@
function main(x: u128) -> u128 {
return x
}

View File

@ -0,0 +1,3 @@
function main(a: u128, b: u128) -> bool {
return a <= b
}

View File

@ -0,0 +1,3 @@
function main(a: u128, b: u128) -> bool {
return a < b
}

View File

@ -0,0 +1,3 @@
function main() -> u128 {
return 340282366920938463463374607431768211455
}

View File

@ -0,0 +1,3 @@
function main() -> u128 {
return 0
}

View File

@ -0,0 +1,50 @@
use crate::{
boolean::{output_expected_boolean, output_false, output_true},
compile_program, get_output,
integer::{fail_integer, fail_synthesis, IntegerTester},
EdwardsConstrainedValue, EdwardsTestCompiler,
};
use leo_compiler::{types::Integer, ConstrainedValue, InputValue};
use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::r1cs::TestConstraintSystem;
use snarkos_models::gadgets::utilities::{alloc::AllocGadget, uint::UInt128};
const DIRECTORY_NAME: &str = "tests/integer/u128/";
fn output_expected_allocated(program: EdwardsTestCompiler, expected: UInt128) {
let output = get_output(program);
match output {
EdwardsConstrainedValue::Return(vec) => match vec.as_slice() {
[ConstrainedValue::Integer(Integer::U128(actual))] => assert_eq!(*actual, expected),
_ => panic!("program output unknown return value"),
},
_ => panic!("program output unknown return value"),
}
}
#[test]
fn test_u128() {
test_uint!(TestU128, u128, UInt128, DIRECTORY_NAME);
TestU128::test_min(std::u128::MIN);
TestU128::test_max(std::u128::MAX);
TestU128::test_input();
TestU128::test_add();
// TestU128::test_sub(); //Todo: Catch subtraction overflow error in gadget
TestU128::test_mul();
TestU128::test_div();
// TestU128::test_pow(); // takes about 10 minutes
TestU128::test_eq();
TestU128::test_ge();
TestU128::test_gt();
TestU128::test_le();
TestU128::test_gt();
TestU128::test_assert_eq();
TestU128::test_ternary();
}

View File

@ -0,0 +1,3 @@
function main(a: u128, b: u128) -> u128 {
return a * b
}

View File

@ -0,0 +1,3 @@
function main() -> u128 {
return 1
}

View File

@ -0,0 +1,3 @@
function main(a: u128, b: u128) -> u128 {
return a ** b
}

View File

@ -0,0 +1,3 @@
function main(a: u128, b: u128) -> u128 {
return a - b
}

View File

@ -0,0 +1,3 @@
function main(b: bool, x: u128, y: u128) -> u128 {
return if b ? x : y
}

View File

@ -0,0 +1,3 @@
function main() -> u128 {
return 0
}

View File

@ -0,0 +1,3 @@
function main(a: u16, b: u16) -> u16 {
return a + b
}

View File

@ -0,0 +1,3 @@
function main(a: u16, b: u16) {
assert_eq!(a, b);
}

View File

@ -0,0 +1,3 @@
function main(a: u16, b: u16) -> u16 {
return a / b
}

View File

@ -0,0 +1,3 @@
function main(a: u16, b: u16) -> bool {
return a == b
}

View File

@ -0,0 +1,3 @@
function main(a: u16, b: u16) -> bool {
return a >= b
}

View File

@ -0,0 +1,3 @@
function main(a: u16, b: u16) -> bool {
return a > b
}

View File

@ -0,0 +1,3 @@
function main(x: u16) -> u16 {
return x
}

View File

@ -0,0 +1,3 @@
function main(a: u16, b: u16) -> bool {
return a <= b
}

View File

@ -0,0 +1,3 @@
function main(a: u16, b: u16) -> bool {
return a < b
}

View File

@ -0,0 +1,3 @@
function main() -> u16 {
return 65535
}

View File

@ -0,0 +1,3 @@
function main() -> u16 {
return 0
}

View File

@ -0,0 +1,50 @@
use crate::{
boolean::{output_expected_boolean, output_false, output_true},
compile_program, get_output,
integer::{fail_integer, fail_synthesis, IntegerTester},
EdwardsConstrainedValue, EdwardsTestCompiler,
};
use leo_compiler::{types::Integer, ConstrainedValue, InputValue};
use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::r1cs::TestConstraintSystem;
use snarkos_models::gadgets::utilities::{alloc::AllocGadget, uint::UInt16};
const DIRECTORY_NAME: &str = "tests/integer/u16/";
fn output_expected_allocated(program: EdwardsTestCompiler, expected: UInt16) {
let output = get_output(program);
match output {
EdwardsConstrainedValue::Return(vec) => match vec.as_slice() {
[ConstrainedValue::Integer(Integer::U16(actual))] => assert_eq!(*actual, expected),
_ => panic!("program output unknown return value"),
},
_ => panic!("program output unknown return value"),
}
}
#[test]
fn test_u16() {
test_uint!(Testu16, u16, UInt16, DIRECTORY_NAME);
Testu16::test_min(std::u16::MIN);
Testu16::test_max(std::u16::MAX);
Testu16::test_input();
Testu16::test_add();
// Testu16::test_sub(); //Todo: Catch subtraction overflow error in gadget
Testu16::test_mul();
Testu16::test_div();
Testu16::test_pow();
Testu16::test_eq();
Testu16::test_ge();
Testu16::test_gt();
Testu16::test_le();
Testu16::test_gt();
Testu16::test_assert_eq();
Testu16::test_ternary();
}

View File

@ -0,0 +1,3 @@
function main(a: u16, b: u16) -> u16 {
return a * b
}

View File

@ -0,0 +1,3 @@
function main() -> u16 {
return 1
}

View File

@ -0,0 +1,3 @@
function main(a: u16, b: u16) -> u16 {
return a ** b
}

View File

@ -0,0 +1,3 @@
function main(a: u16, b: u16) -> u16 {
return a - b
}

View File

@ -0,0 +1,3 @@
function main(b: bool, x: u16, y: u16) -> u16 {
return if b ? x : y
}

View File

@ -0,0 +1,3 @@
function main() -> u16 {
return 0
}

View File

@ -1,4 +0,0 @@
// This program should panic at compilation.
function main() -> u32 {
return 1 - 2
}

View File

@ -0,0 +1,3 @@
function main(a: u32, b: u32) -> u32 {
return a + b
}

View File

@ -0,0 +1,3 @@
function main(a: u32, b: u32) {
assert_eq!(a, b);
}

View File

@ -0,0 +1,3 @@
function main(a: u32, b: u32) -> u32 {
return a / b
}

View File

@ -0,0 +1,3 @@
function main(a: u32, b: u32) -> bool {
return a == b
}

View File

@ -0,0 +1,3 @@
function main(a: u32, b: u32) -> bool {
return a >= b
}

View File

@ -0,0 +1,3 @@
function main(a: u32, b: u32) -> bool {
return a > b
}

View File

@ -0,0 +1,3 @@
function main(a: u32, b: u32) -> bool {
return a <= b
}

View File

@ -0,0 +1,3 @@
function main(a: u32, b: u32) -> bool {
return a < b
}

View File

@ -1,3 +1,3 @@
function main() -> u32 {
return 1 - 1
}
return 4294967295
}

View File

@ -1,3 +1,3 @@
function main() -> u32 {
return 1 + 1
}
return 0
}

View File

@ -1,14 +1,29 @@
use crate::{compile_program, get_error, get_output, EdwardsConstrainedValue, EdwardsTestCompiler};
use leo_compiler::{
errors::{CompilerError, FunctionError, IntegerError},
types::Integer,
ConstrainedValue, InputValue,
use crate::{
boolean::{output_expected_boolean, output_false, output_true},
compile_program, get_output,
integer::{fail_integer, fail_synthesis, IntegerTester},
EdwardsConstrainedValue, EdwardsTestCompiler,
};
use leo_compiler::{types::Integer, ConstrainedValue, InputValue};
use snarkos_models::gadgets::utilities::uint::UInt32;
use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::r1cs::TestConstraintSystem;
use snarkos_models::gadgets::utilities::{alloc::AllocGadget, uint::UInt32};
const DIRECTORY_NAME: &str = "tests/integer/u32/";
fn output_expected_allocated(program: EdwardsTestCompiler, expected: UInt32) {
let output = get_output(program);
match output {
EdwardsConstrainedValue::Return(vec) => match vec.as_slice() {
[ConstrainedValue::Integer(Integer::U32(actual))] => assert_eq!(*actual, expected),
_ => panic!("program output unknown return value"),
},
_ => panic!("program output unknown return value"),
}
}
pub(crate) fn output_zero(program: EdwardsTestCompiler) {
let output = get_output(program);
assert_eq!(
@ -31,47 +46,29 @@ pub(crate) fn output_one(program: EdwardsTestCompiler) {
)
}
fn output_two(program: EdwardsTestCompiler) {
let output = get_output(program);
assert_eq!(
EdwardsConstrainedValue::Return(vec![ConstrainedValue::Integer(Integer::U32(
UInt32::constant(2u32)
))])
.to_string(),
output.to_string()
)
}
fn fail_integer(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::IntegerError(
IntegerError::InvalidInteger(_string),
)) => {}
error => panic!("Expected invalid boolean error, got {}", error),
}
}
fn fail_synthesis(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::IntegerError(
IntegerError::SynthesisError(_string),
)) => {}
error => panic!("Expected synthesis error, got {}", error),
}
}
#[test]
fn test_input_u32_bool() {
let mut program = compile_program(DIRECTORY_NAME, "input_u32.leo").unwrap();
program.set_inputs(vec![Some(InputValue::Boolean(true))]);
fail_integer(program);
}
fn test_u32() {
test_uint!(TestU32, u32, UInt32, DIRECTORY_NAME);
#[test]
fn test_input_u32_none() {
let mut program = compile_program(DIRECTORY_NAME, "input_u32.leo").unwrap();
program.set_inputs(vec![None]);
fail_synthesis(program);
TestU32::test_min(std::u32::MIN);
TestU32::test_max(std::u32::MAX);
TestU32::test_input();
TestU32::test_add();
// TestU32::test_sub(); //Todo: Catch subtraction overflow error in gadget
TestU32::test_mul();
TestU32::test_div();
TestU32::test_pow(); // takes about 2 mins
TestU32::test_eq();
TestU32::test_ge();
TestU32::test_gt();
TestU32::test_le();
TestU32::test_gt();
TestU32::test_assert_eq();
TestU32::test_ternary();
}
#[test]
@ -85,22 +82,3 @@ fn test_one() {
let program = compile_program(DIRECTORY_NAME, "one.leo").unwrap();
output_one(program);
}
#[test]
fn test_1_plus_1() {
let program = compile_program(DIRECTORY_NAME, "1+1.leo").unwrap();
output_two(program);
}
#[test]
fn test_1_minus_1() {
let program = compile_program(DIRECTORY_NAME, "1-1.leo").unwrap();
output_zero(program)
}
// #[test] // Todo: Catch subtraction overflow error in gadget
// fn test_1_minus_2() {
// let program = compile_program(DIRECTORY_NAME, "1-2.leo").unwrap();
// let error = get_error(program);
// println!("{}", error);
// }

View File

@ -0,0 +1,3 @@
function main(a: u32, b: u32) -> u32 {
return a * b
}

View File

@ -0,0 +1,3 @@
function main(a: u32, b: u32) -> u32 {
return a ** b
}

View File

@ -0,0 +1,3 @@
function main(a: u32, b: u32) -> u32 {
return a - b
}

View File

@ -0,0 +1,3 @@
function main(b: bool, x: u32, y: u32) -> u32 {
return if b ? x : y
}

View File

@ -0,0 +1,3 @@
function main(a: u64, b: u64) -> u64 {
return a + b
}

View File

@ -0,0 +1,3 @@
function main(a: u64, b: u64) {
assert_eq!(a, b);
}

View File

@ -0,0 +1,3 @@
function main(a: u64, b: u64) -> u64 {
return a / b
}

View File

@ -0,0 +1,3 @@
function main(a: u64, b: u64) -> bool {
return a == b
}

View File

@ -0,0 +1,3 @@
function main(a: u64, b: u64) -> bool {
return a >= b
}

View File

@ -0,0 +1,3 @@
function main(a: u64, b: u64) -> bool {
return a > b
}

View File

@ -0,0 +1,3 @@
function main(x: u64) -> u64 {
return x
}

View File

@ -0,0 +1,3 @@
function main(a: u64, b: u64) -> bool {
return a <= b
}

View File

@ -0,0 +1,3 @@
function main(a: u64, b: u64) -> bool {
return a < b
}

View File

@ -0,0 +1,3 @@
function main() -> u64 {
return 18446744073709551615
}

View File

@ -0,0 +1,3 @@
function main() -> u64 {
return 0
}

View File

@ -0,0 +1,50 @@
use crate::{
boolean::{output_expected_boolean, output_false, output_true},
compile_program, get_output,
integer::{fail_integer, fail_synthesis, IntegerTester},
EdwardsConstrainedValue, EdwardsTestCompiler,
};
use leo_compiler::{types::Integer, ConstrainedValue, InputValue};
use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::r1cs::TestConstraintSystem;
use snarkos_models::gadgets::utilities::{alloc::AllocGadget, uint::UInt64};
const DIRECTORY_NAME: &str = "tests/integer/u64/";
fn output_expected_allocated(program: EdwardsTestCompiler, expected: UInt64) {
let output = get_output(program);
match output {
EdwardsConstrainedValue::Return(vec) => match vec.as_slice() {
[ConstrainedValue::Integer(Integer::U64(actual))] => assert_eq!(*actual, expected),
_ => panic!("program output unknown return value"),
},
_ => panic!("program output unknown return value"),
}
}
#[test]
fn test_u64() {
test_uint!(Testu64, u64, UInt64, DIRECTORY_NAME);
Testu64::test_min(std::u64::MIN);
Testu64::test_max(std::u64::MAX);
Testu64::test_input();
Testu64::test_add();
// Testu64::test_sub(); //Todo: Catch subtraction overflow error in gadget
Testu64::test_mul();
Testu64::test_div();
Testu64::test_pow(); // takes ~2mins
Testu64::test_eq();
Testu64::test_ge();
Testu64::test_gt();
Testu64::test_le();
Testu64::test_gt();
Testu64::test_assert_eq();
Testu64::test_ternary();
}

View File

@ -0,0 +1,3 @@
function main(a: u64, b: u64) -> u64 {
return a * b
}

View File

@ -0,0 +1,3 @@
function main() -> u64 {
return 1
}

View File

@ -0,0 +1,3 @@
function main(a: u64, b: u64) -> u64 {
return a ** b
}

View File

@ -0,0 +1,3 @@
function main(a: u64, b: u64) -> u64 {
return a - b
}

View File

@ -0,0 +1,3 @@
function main(b: bool, x: u64, y: u64) -> u64 {
return if b ? x : y
}

View File

@ -0,0 +1,3 @@
function main() -> u64 {
return 0
}

View File

@ -0,0 +1,3 @@
function main(a: u8, b: u8) -> u8 {
return a + b
}

View File

@ -0,0 +1,3 @@
function main(a: u8, b: u8) {
assert_eq!(a, b);
}

View File

@ -0,0 +1,3 @@
function main(a: u8, b: u8) -> u8 {
return a / b
}

View File

@ -0,0 +1,3 @@
function main(a: u8, b: u8) -> bool {
return a == b
}

View File

@ -0,0 +1,3 @@
function main(a: u8, b: u8) -> bool {
return a >= b
}

View File

@ -0,0 +1,3 @@
function main(a: u8, b: u8) -> bool {
return a > b
}

View File

@ -0,0 +1,3 @@
function main(x: u8) -> u8 {
return x
}

View File

@ -0,0 +1,3 @@
function main(a: u8, b: u8) -> bool {
return a <= b
}

View File

@ -0,0 +1,3 @@
function main(a: u8, b: u8) -> bool {
return a < b
}

View File

@ -0,0 +1,3 @@
function main() -> u8 {
return 255
}

View File

@ -0,0 +1,3 @@
function main() -> u8 {
return 0
}

View File

@ -0,0 +1,50 @@
use crate::{
boolean::{output_expected_boolean, output_false, output_true},
compile_program, get_output,
integer::{fail_integer, fail_synthesis, IntegerTester},
EdwardsConstrainedValue, EdwardsTestCompiler,
};
use leo_compiler::{types::Integer, ConstrainedValue, InputValue};
use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::r1cs::TestConstraintSystem;
use snarkos_models::gadgets::utilities::{alloc::AllocGadget, uint::UInt8};
const DIRECTORY_NAME: &str = "tests/integer/u8/";
fn output_expected_allocated(program: EdwardsTestCompiler, expected: UInt8) {
let output = get_output(program);
match output {
EdwardsConstrainedValue::Return(vec) => match vec.as_slice() {
[ConstrainedValue::Integer(Integer::U8(actual))] => assert_eq!(*actual, expected),
_ => panic!("program output unknown return value"),
},
_ => panic!("program output unknown return value"),
}
}
#[test]
fn test_u8() {
test_uint!(Testu8, u8, UInt8, DIRECTORY_NAME);
Testu8::test_min(std::u8::MIN);
Testu8::test_max(std::u8::MAX);
Testu8::test_input();
Testu8::test_add();
// Testu8::test_sub(); //Todo: Catch subtraction overflow error in gadget
Testu8::test_mul();
Testu8::test_div();
Testu8::test_pow();
Testu8::test_eq();
Testu8::test_ge();
Testu8::test_gt();
Testu8::test_le();
Testu8::test_gt();
Testu8::test_assert_eq();
Testu8::test_ternary();
}

Some files were not shown because too many files have changed in this diff Show More