Merge pull request #122 from AleoHQ/feature/runtime-state

Feature/runtime state
This commit is contained in:
Collin Chin 2020-07-31 15:03:28 -07:00 committed by GitHub
commit 17e2adcdb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
446 changed files with 4384 additions and 2698 deletions

1
Cargo.lock generated
View File

@ -609,6 +609,7 @@ dependencies = [
"pest",
"rand",
"rand_xorshift",
"serde",
"sha2",
"snarkos-curves",
"snarkos-dpc",

View File

@ -1,4 +1,4 @@
use crate::{ast::Rule, common::Identifier, functions::FunctionInput, statements::Statement, types::Type, SpanDef};
use crate::{ast::Rule, common::Identifier, functions::input::Input, statements::Statement, types::Type, SpanDef};
use pest::Span;
use pest_ast::FromPest;
@ -8,7 +8,7 @@ use serde::Serialize;
#[pest_ast(rule(Rule::function_definition))]
pub struct Function<'ast> {
pub function_name: Identifier<'ast>,
pub parameters: Vec<FunctionInput<'ast>>,
pub parameters: Vec<Input<'ast>>,
pub returns: Vec<Type<'ast>>,
pub statements: Vec<Statement<'ast>>,
#[pest_ast(outer())]

View File

@ -0,0 +1,17 @@
use crate::{
ast::Rule,
functions::{FunctionInput, Record, Registers, State, StateLeaf},
};
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::input))]
pub enum Input<'ast> {
FunctionInput(FunctionInput<'ast>),
Record(Record<'ast>),
Registers(Registers<'ast>),
State(State<'ast>),
StateLeaf(StateLeaf<'ast>),
}

View File

@ -0,0 +1,17 @@
pub mod function_input;
pub use function_input::*;
pub mod input;
pub use input::*;
pub mod record;
pub use record::*;
pub mod registers;
pub use registers::*;
pub mod state;
pub use state::*;
pub mod state_leaf;
pub use state_leaf::*;

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::record))]
pub struct Record<'ast> {
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::registers))]
pub struct Registers<'ast> {
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::state))]
pub struct State<'ast> {
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::state_leaf))]
pub struct StateLeaf<'ast> {
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -1,8 +1,8 @@
pub mod function;
pub use function::*;
pub mod function_input;
pub use function_input::*;
pub mod inputs;
pub use inputs::*;
pub mod test_function;
pub use test_function::*;

View File

@ -335,11 +335,32 @@ statement_return = { "return " ~ return_}
/// Functions
// Declared in functions/function.rs
function_definition = { "function " ~ identifier ~ "(" ~ NEWLINE* ~ input_model_list ~ NEWLINE* ~ ")" ~ ("->" ~ (type_ | "(" ~ type_list ~ ")"))? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* }
function_definition = { "function " ~ identifier ~ "(" ~ NEWLINE* ~ input_list ~ NEWLINE* ~ ")" ~ ("->" ~ (type_ | "(" ~ type_list ~ ")"))? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* }
// Declared in functions/function_input.rs
// Declared in functions/inputs/function_input.rs
function_input = { mutable? ~ identifier ~ ":" ~ type_ }
input_model_list = _{ (function_input ~ ("," ~ NEWLINE* ~ function_input)*)? }
// Declared in functions/inputs/record.rs
record = { "record" }
// Declared in functions/inputs/registers.rs
registers = { "registers" }
// Declared in functions/inputs/state.rs
state = { "state" }
// Declared in functions/inputs/state_leaf.rs
state_leaf = { "state_leaf" }
// Declared in functions/inputs/input.rs
input = {
record
| registers
| state_leaf
| state
| function_input
}
input_list = _{ (input ~ ("," ~ NEWLINE* ~ input)*)? }
// Declared in functions/test_function.rs
test_function = { "test " ~ function_definition }

View File

@ -24,8 +24,9 @@ log = { version = "0.4" }
pest = { version = "2.0" }
rand = { version = "0.7" }
rand_xorshift = { version = "0.2", default-features = false }
serde = { version = "1.0" }
sha2 = { version = "0.9" }
thiserror = { version = "1.0" }
[dev-dependencies]
num-bigint = { version = "0.3" }
num-bigint = { version = "0.3" }

View File

@ -3,13 +3,14 @@
use crate::{
constraints::{generate_constraints, generate_test_constraints},
errors::CompilerError,
value::ConstrainedValue,
GroupType,
ImportParser,
OutputBytes,
OutputsFile,
};
use leo_ast::LeoParser;
use leo_inputs::LeoInputsParser;
use leo_types::{InputValue, Inputs, Program};
use leo_types::{Inputs, MainInputs, Program};
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
@ -24,43 +25,98 @@ use std::{fs, marker::PhantomData, path::PathBuf};
pub struct Compiler<F: Field + PrimeField, G: GroupType<F>> {
package_name: String,
main_file_path: PathBuf,
outputs_directory: PathBuf,
program: Program,
program_inputs: Inputs,
imported_programs: ImportParser,
output: Option<ConstrainedValue<F, G>>,
_engine: PhantomData<F>,
_group: PhantomData<G>,
}
impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
pub fn new(package_name: String) -> Self {
pub fn new(package_name: String, main_file_path: PathBuf, outputs_directory: PathBuf) -> Self {
Self {
package_name: package_name.clone(),
main_file_path: PathBuf::new(),
main_file_path,
outputs_directory,
program: Program::new(package_name),
program_inputs: Inputs::new(),
imported_programs: ImportParser::new(),
output: None,
_engine: PhantomData,
_group: PhantomData,
}
}
pub fn new_from_path(package_name: String, main_file_path: PathBuf) -> Result<Self, CompilerError> {
let mut compiler = Self::new(package_name);
compiler.set_path(main_file_path);
/// Parses program files.
/// Returns a compiler struct that stores the typed program abstract syntax trees (ast).
pub fn parse_program_without_inputs(
package_name: String,
main_file_path: PathBuf,
outputs_directory: PathBuf,
) -> Result<Self, CompilerError> {
let mut compiler = Self::new(package_name, main_file_path, outputs_directory);
// Generate the abstract syntax tree and assemble the program
let program_string = compiler.load_program()?;
compiler.parse_program(&program_string)?;
Ok(compiler)
}
pub fn set_path(&mut self, main_file_path: PathBuf) {
self.main_file_path = main_file_path
/// Parses input, state, and program files.
/// Returns a compiler struct that stores the typed inputs and typed program abstract syntax trees (ast).
pub fn parse_program_with_inputs(
package_name: String,
main_file_path: PathBuf,
outputs_directory: PathBuf,
inputs_string: &str,
state_string: &str,
) -> Result<Self, CompilerError> {
let mut compiler = Self::new(package_name, main_file_path, outputs_directory);
compiler.parse_inputs(inputs_string, state_string)?;
let program_string = compiler.load_program()?;
compiler.parse_program(&program_string)?;
Ok(compiler)
}
pub fn set_inputs(&mut self, program_inputs: Vec<Option<InputValue>>) {
self.program_inputs.set_inputs(program_inputs);
/// Parse the input and state files.
/// Stores a typed ast of all inputs to the program.
pub fn parse_inputs(&mut self, inputs_string: &str, state_string: &str) -> Result<(), CompilerError> {
let inputs_syntax_tree = LeoInputsParser::parse_file(&inputs_string)?;
let state_syntax_tree = LeoInputsParser::parse_file(&state_string)?;
self.program_inputs.parse_inputs(inputs_syntax_tree)?;
self.program_inputs.parse_state(state_syntax_tree)?;
Ok(())
}
/// Parse the program file and all associated import files.
pub fn parse_program(&mut self, program_string: &str) -> Result<(), CompilerError> {
// Parse the program syntax tree
let syntax_tree = LeoParser::parse_file(&self.main_file_path, program_string)?;
// Build program from syntax tree
let package_name = self.package_name.clone();
self.program = Program::from(syntax_tree, package_name);
self.imported_programs = ImportParser::parse(&self.program)?;
log::debug!("Program parsing complete\n{:#?}", self.program);
Ok(())
}
/// Loads the program file at `main_file_path`.
fn load_program(&mut self) -> Result<String, CompilerError> {
Ok(LeoParser::load_file(&self.main_file_path)?)
}
/// Manually sets main function inputs
pub fn set_main_inputs(&mut self, inputs: MainInputs) {
self.program_inputs.set_main_inputs(inputs);
}
pub fn checksum(&self) -> Result<String, CompilerError> {
@ -76,53 +132,36 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
Ok(hex::encode(hash))
}
pub fn compile_constraints<CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
) -> Result<ConstrainedValue<F, G>, CompilerError> {
/// Synthesizes the circuit without program inputs to verify correctness.
pub fn compile_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<OutputBytes, CompilerError> {
let path = self.main_file_path;
let inputs = self.program_inputs.get_inputs();
let inputs = self.program_inputs.empty();
generate_constraints(cs, self.program, inputs, &self.imported_programs).map_err(|mut error| {
generate_constraints::<F, G, CS>(cs, self.program, inputs, &self.imported_programs).map_err(|mut error| {
error.set_path(path);
error
})
}
/// Synthesizes the circuit for test functions with program inputs.
pub fn compile_test_constraints(self, cs: &mut TestConstraintSystem<F>) -> Result<(), CompilerError> {
generate_test_constraints::<F, G>(cs, self.program, &self.imported_programs)
generate_test_constraints::<F, G>(cs, self.program, self.program_inputs, &self.imported_programs)
}
/// Loads the Leo code as a string from the given file path.
fn load_program(&mut self) -> Result<String, CompilerError> {
Ok(LeoParser::load_file(&self.main_file_path)?)
}
/// Calls the internal generate_constraints method with arguments
pub fn generate_constraints_helper<CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
) -> Result<OutputBytes, CompilerError> {
let path = self.main_file_path;
generate_constraints::<_, G, _>(cs, self.program, self.program_inputs, &self.imported_programs).map_err(
|mut error| {
error.set_path(path);
/// Parses the Leo program string, constructs a syntax tree, and generates a program.
pub fn parse_program(&mut self, program_string: &str) -> Result<(), CompilerError> {
// Parse the program syntax tree
let syntax_tree = LeoParser::parse_file(&self.main_file_path, program_string)?;
// Build program from syntax tree
let package_name = self.package_name.clone();
self.program = Program::from(syntax_tree, package_name);
self.program_inputs.set_inputs_size(self.program.expected_inputs.len());
self.imported_programs = ImportParser::parse(&self.program)?;
log::debug!("Program parsing complete\n{:#?}", self.program);
Ok(())
}
pub fn parse_inputs(&mut self, inputs_string: &str) -> Result<(), CompilerError> {
let syntax_tree = LeoInputsParser::parse_file(&inputs_string)?;
// Check number/order of parameters here
self.program_inputs = Inputs::from_inputs_file(syntax_tree, self.program.expected_inputs.clone())?;
Ok(())
error
},
)
}
pub fn to_bytes(&self) -> Result<Vec<u8>, CompilerError> {
@ -131,37 +170,36 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CompilerError> {
let program: Program = bincode::deserialize(bytes)?;
let mut program_inputs = Inputs::new();
program_inputs.set_inputs_size(program.expected_inputs.len());
let program_inputs = Inputs::new();
Ok(Self {
package_name: program.name.clone(),
main_file_path: PathBuf::new(),
outputs_directory: PathBuf::new(),
program,
program_inputs,
imported_programs: ImportParser::new(),
output: None,
_engine: PhantomData,
_group: PhantomData,
})
}
}
impl<F: Field + PrimeField, G: GroupType<F>> ConstraintSynthesizer<F> for Compiler<F, G> {
/// Synthesizes the circuit with program inputs.
fn generate_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
let result = generate_constraints::<_, G, _>(
cs,
self.program,
self.program_inputs.get_inputs(),
&self.imported_programs,
)
.map_err(|e| {
let outputs_directory = self.outputs_directory.clone();
let package_name = self.package_name.clone();
let result = self.generate_constraints_helper(cs).map_err(|e| {
log::error!("{}", e);
SynthesisError::Unsatisfiable
})?;
// Write results to file or something
log::info!("{}", result);
log::info!("Program circuit successfully synthesized!");
// Write results to file
let outputs_file = OutputsFile::new(&package_name);
outputs_file.write(&outputs_directory, result.bytes()).unwrap();
Ok(())
}

View File

@ -1,7 +1,15 @@
//! Generates R1CS constraints for a compiled Leo program.
use crate::{errors::CompilerError, new_scope, ConstrainedProgram, ConstrainedValue, GroupType, ImportParser};
use leo_types::{InputValue, Program};
use crate::{
errors::CompilerError,
new_scope,
ConstrainedProgram,
ConstrainedValue,
GroupType,
ImportParser,
OutputBytes,
};
use leo_types::{Inputs, Program};
use snarkos_models::{
curves::{Field, PrimeField},
@ -11,10 +19,10 @@ use snarkos_models::{
pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
cs: &mut CS,
program: Program,
parameters: Vec<Option<InputValue>>,
inputs: Inputs,
imported_programs: &ImportParser,
) -> Result<ConstrainedValue<F, G>, CompilerError> {
let mut resolved_program = ConstrainedProgram::new();
) -> Result<OutputBytes, CompilerError> {
let mut resolved_program = ConstrainedProgram::<F, G>::new();
let program_name = program.get_name();
let main_function_name = new_scope(program_name.clone(), "main".into());
@ -26,7 +34,7 @@ pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
match main.clone() {
ConstrainedValue::Function(_circuit_identifier, function) => {
let result = resolved_program.enforce_main_function(cs, program_name, function, parameters)?;
let result = resolved_program.enforce_main_function(cs, program_name, function, inputs)?;
Ok(result)
}
_ => Err(CompilerError::NoMainFunction),
@ -36,6 +44,7 @@ pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
cs: &mut TestConstraintSystem<F>,
program: Program,
inputs: Inputs,
imported_programs: &ImportParser,
) -> Result<(), CompilerError> {
let mut resolved_program = ConstrainedProgram::<F, G>::new();
@ -54,7 +63,7 @@ pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
cs,
program_name.clone(),
test_function.0,
vec![], // test functions should not take any inputs
inputs.clone(), // pass program inputs into every test
);
if result.is_ok() {

View File

@ -1,4 +1,4 @@
use crate::errors::{FunctionError, ImportError};
use crate::errors::{FunctionError, ImportError, OutputBytesError, OutputsFileError};
use leo_ast::ParserError;
use leo_inputs::InputParserError;
@ -25,6 +25,12 @@ pub enum CompilerError {
#[error("`main` must be a function")]
NoMainFunction,
#[error("{}", _0)]
OutputError(#[from] OutputsFileError),
#[error("{}", _0)]
OutputStringError(#[from] OutputBytesError),
#[error("{}", _0)]
ParserError(#[from] ParserError),
@ -36,6 +42,7 @@ impl CompilerError {
pub fn set_path(&mut self, path: PathBuf) {
match self {
CompilerError::FunctionError(error) => error.set_path(path),
CompilerError::OutputStringError(error) => error.set_path(path),
_ => {}
}
}

View File

@ -5,6 +5,7 @@ use crate::errors::{
FieldError,
GroupError,
IntegerError,
OutputBytesError,
StatementError,
ValueError,
};
@ -35,6 +36,9 @@ pub enum FunctionError {
#[error("{}", _0)]
IntegerError(#[from] IntegerError),
#[error("{}", _0)]
OutputStringError(#[from] OutputBytesError),
#[error("{}", _0)]
StatementError(#[from] StatementError),
@ -52,6 +56,7 @@ impl FunctionError {
FunctionError::FieldError(error) => error.set_path(path),
FunctionError::GroupError(error) => error.set_path(path),
FunctionError::IntegerError(error) => error.set_path(path),
FunctionError::OutputStringError(error) => error.set_path(path),
FunctionError::StatementError(error) => error.set_path(path),
FunctionError::ValueError(error) => error.set_path(path),
}
@ -78,4 +83,10 @@ impl FunctionError {
Self::new_from_span(message, span)
}
pub fn input_not_found(expected: String, span: Span) -> Self {
let message = format!("main function input {} not found", expected);
Self::new_from_span(message, span)
}
}

View File

@ -13,6 +13,12 @@ pub use self::import::*;
pub mod macro_;
pub use self::macro_::*;
pub mod output_file;
pub use self::output_file::*;
pub mod output_bytes;
pub use self::output_bytes::*;
pub mod statement;
pub use self::statement::*;

View File

@ -0,0 +1,33 @@
use leo_types::{Error as FormattedError, Span};
use std::path::PathBuf;
#[derive(Debug, Error)]
pub enum OutputBytesError {
#[error("{}", _0)]
Error(#[from] FormattedError),
}
impl OutputBytesError {
pub fn set_path(&mut self, path: PathBuf) {
match self {
OutputBytesError::Error(error) => error.set_path(path),
}
}
fn new_from_span(message: String, span: Span) -> Self {
OutputBytesError::Error(FormattedError::new_from_span(message, span))
}
pub fn illegal_return(value: String, span: Span) -> Self {
let message = format!("program return must be a return value, found `{}`", value);
Self::new_from_span(message, span)
}
pub fn not_enough_registers(span: Span) -> Self {
let message = format!("number of input registers must be greater than or equal to output registers");
Self::new_from_span(message, span)
}
}

View File

@ -0,0 +1,22 @@
use std::{io, path::PathBuf};
#[derive(Debug, Error)]
pub enum OutputsFileError {
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
#[error("creating: {}", _0)]
Creating(io::Error),
#[error("Cannot read from the provided file path - {:?}", _0)]
FileReadError(PathBuf),
#[error("writing: {}", _0)]
Writing(io::Error),
}
impl From<std::io::Error> for OutputsFileError {
fn from(error: std::io::Error) -> Self {
OutputsFileError::Crate("std::io", format!("{}", error))
}
}

View File

@ -7,7 +7,7 @@ use crate::{
GroupType,
};
use leo_types::{Expression, Function, Span};
use leo_types::{Expression, Function, Input, Span};
use snarkos_models::{
curves::{Field, PrimeField},
@ -39,23 +39,77 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Store input values as new variables in resolved program
for (input_model, input_expression) in function.inputs.clone().iter().zip(inputs.into_iter()) {
// First evaluate input expression
let mut input_value = self.enforce_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
vec![input_model._type.clone()],
input_expression,
)?;
let (name, value) = match input_model {
Input::FunctionInput(input_model) => {
// First evaluate input expression
let mut input_value = self.enforce_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
vec![input_model.type_.clone()],
input_expression,
)?;
if input_model.mutable {
input_value = ConstrainedValue::Mutable(Box::new(input_value))
}
if input_model.mutable {
input_value = ConstrainedValue::Mutable(Box::new(input_value))
}
(input_model.identifier.name.clone(), input_value)
}
Input::Registers(identifier) => {
let input_value = self.enforce_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
vec![],
input_expression,
)?;
(identifier.name.clone(), input_value)
}
Input::Record(identifier) => {
let input_value = self.enforce_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
vec![],
input_expression,
)?;
(identifier.name.clone(), input_value)
}
Input::State(identifier) => {
let input_value = self.enforce_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
vec![],
input_expression,
)?;
(identifier.name.clone(), input_value)
}
Input::StateLeaf(identifier) => {
let input_value = self.enforce_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
vec![],
input_expression,
)?;
(identifier.name.clone(), input_value)
}
};
// Store input as variable with {function_name}_{input_name}
let input_program_identifier = new_scope(function_name.clone(), input_model.identifier.name.clone());
self.store(input_program_identifier, input_value);
let input_program_identifier = new_scope(function_name.clone(), name);
self.store(input_program_identifier, value);
}
// Evaluate every statement in the function and save all potential results

View File

@ -2,7 +2,6 @@
use crate::{
errors::FunctionError,
function::check_arguments_length,
program::{new_scope, ConstrainedProgram},
value::ConstrainedValue,
GroupType,
@ -30,9 +29,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
match input_value {
Some(InputValue::Array(arr)) => {
// Check the dimension of the array
check_arguments_length(expected_length, arr.len(), span.clone())?;
// Allocate each value in the current row
for (i, value) in arr.into_iter().enumerate() {
let value_name = new_scope(name.clone(), i.to_string());

View File

@ -25,24 +25,24 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn allocate_main_function_input<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
_type: Type,
type_: Type,
name: String,
input_value: Option<InputValue>,
input_option: Option<InputValue>,
span: Span,
) -> Result<ConstrainedValue<F, G>, FunctionError> {
match _type {
Type::Address => Ok(Address::from_input(cs, name, input_value, span)?),
Type::Boolean => Ok(bool_from_input(cs, name, input_value, span)?),
Type::Field => Ok(field_from_input(cs, name, input_value, span)?),
Type::Group => Ok(group_from_input(cs, name, input_value, span)?),
match type_ {
Type::Address => Ok(Address::from_input(cs, name, input_option, span)?),
Type::Boolean => Ok(bool_from_input(cs, name, input_option, span)?),
Type::Field => Ok(field_from_input(cs, name, input_option, span)?),
Type::Group => Ok(group_from_input(cs, name, input_option, span)?),
Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(Integer::from_input(
cs,
integer_type,
name,
input_value,
input_option,
span,
)?)),
Type::Array(_type, dimensions) => self.allocate_array(cs, name, *_type, dimensions, input_value, span),
Type::Array(_type, dimensions) => self.allocate_array(cs, name, *_type, dimensions, input_option, span),
_ => unimplemented!("main function input not implemented for type"),
}
}

View File

@ -8,3 +8,6 @@ pub use self::input::*;
pub mod main_input;
pub use self::main_input::*;
pub mod section;
pub use self::section::*;

View File

@ -0,0 +1,37 @@
use crate::{errors::FunctionError, ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, GroupType};
use leo_types::{Identifier, InputValue, Parameter};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
use std::collections::HashMap;
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn allocate_input_section<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
identifier: Identifier,
section: HashMap<Parameter, Option<InputValue>>,
) -> Result<ConstrainedValue<F, G>, FunctionError> {
let mut members = vec![];
// Store each section definition as a circuit member value
for (parameter, option) in section.into_iter() {
let member_name = parameter.variable.clone();
let member_value = self.allocate_main_function_input(
cs,
parameter.type_,
parameter.variable.name,
option,
parameter.span,
)?;
let member = ConstrainedCircuitMember(member_name, member_value);
members.push(member)
}
// Return section as circuit expression
Ok(ConstrainedValue::CircuitExpression(identifier, members))
}
}

View File

@ -2,13 +2,12 @@
use crate::{
errors::FunctionError,
function::check_arguments_length,
program::{new_scope, ConstrainedProgram},
value::ConstrainedValue,
GroupType,
OutputBytes,
};
use leo_types::{Expression, Function, InputValue};
use leo_types::{Expression, Function, Input, Inputs};
use snarkos_models::{
curves::{Field, PrimeField},
@ -21,31 +20,69 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS,
scope: String,
function: Function,
inputs: Vec<Option<InputValue>>,
) -> Result<ConstrainedValue<F, G>, FunctionError> {
inputs: Inputs,
) -> Result<OutputBytes, FunctionError> {
let function_name = new_scope(scope.clone(), function.get_name());
// Make sure we are given the correct number of inputs
check_arguments_length(function.inputs.len(), inputs.len(), function.span.clone())?;
let registers = inputs.get_registers();
// Iterate over main function inputs and allocate new passed-by variable values
let mut input_variables = vec![];
for (input_model, input_option) in function.inputs.clone().into_iter().zip(inputs.into_iter()) {
let input_value = self.allocate_main_function_input(
cs,
input_model._type,
input_model.identifier.name.clone(),
input_option,
function.span.clone(),
)?;
for input_model in function.inputs.clone().into_iter() {
let (identifier, value) = match input_model {
Input::FunctionInput(input_model) => {
let name = input_model.identifier.name.clone();
let input_option = inputs
.get(&name)
.ok_or(FunctionError::input_not_found(name.clone(), function.span.clone()))?;
let input_value = self.allocate_main_function_input(
cs,
input_model.type_,
name.clone(),
input_option,
function.span.clone(),
)?;
(input_model.identifier, input_value)
}
Input::Registers(identifier) => {
let section = inputs.get_registers().values();
let value = self.allocate_input_section(cs, identifier.clone(), section)?;
(identifier, value)
}
Input::Record(identifier) => {
let section = inputs.get_record().values();
let value = self.allocate_input_section(cs, identifier.clone(), section)?;
(identifier, value)
}
Input::State(identifier) => {
let section = inputs.get_state().values();
let value = self.allocate_input_section(cs, identifier.clone(), section)?;
(identifier, value)
}
Input::StateLeaf(identifier) => {
let section = inputs.get_state_leaf().values();
let value = self.allocate_input_section(cs, identifier.clone(), section)?;
(identifier, value)
}
};
// Store input as variable with {function_name}_{identifier_name}
let input_name = new_scope(function_name.clone(), identifier.name.clone());
// Store a new variable for every allocated main function input
let input_name = new_scope(function_name.clone(), input_model.identifier.name.clone());
self.store(input_name.clone(), input_value);
self.store(input_name, value);
input_variables.push(Expression::Identifier(input_model.identifier));
input_variables.push(Expression::Identifier(identifier));
}
self.enforce_function(cs, scope, function_name, function, input_variables)
let span = function.span.clone();
let result_value = self.enforce_function(cs, scope, function_name, function, input_variables)?;
let output_bytes = OutputBytes::new_from_constrained_value(registers, result_value, span)?;
Ok(output_bytes)
}
}

View File

@ -24,6 +24,9 @@ pub use self::import::*;
pub mod macro_;
pub use self::macro_::*;
pub mod output;
pub use self::output::*;
pub mod program;
pub use self::program::*;

View File

@ -0,0 +1,5 @@
pub mod output_file;
pub use self::output_file::*;
pub mod output_bytes;
pub use self::output_bytes::*;

View File

@ -0,0 +1,69 @@
use crate::{errors::OutputBytesError, ConstrainedValue, GroupType};
use leo_types::{Parameter, Registers, Span, REGISTERS_VARIABLE_NAME};
use snarkos_models::curves::{Field, PrimeField};
use serde::{Deserialize, Serialize};
/// Serialized program return output.
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
pub struct OutputBytes(Vec<u8>);
impl OutputBytes {
pub fn bytes(&self) -> &Vec<u8> {
&self.0
}
pub fn new_from_constrained_value<F: Field + PrimeField, G: GroupType<F>>(
registers: &Registers,
value: ConstrainedValue<F, G>,
span: Span,
) -> Result<Self, OutputBytesError> {
let return_values = match value {
ConstrainedValue::Return(values) => values,
value => return Err(OutputBytesError::illegal_return(value.to_string(), span)),
};
let register_hashmap = registers.values();
// Create vector of parameter values in alphabetical order
let mut register_values = register_hashmap
.into_iter()
.map(|register| register.0)
.collect::<Vec<Parameter>>();
register_values.sort_by(|a, b| a.variable.name.cmp(&b.variable.name));
// Return an error if we do not have enough return registers
if register_values.len() < return_values.len() {
return Err(OutputBytesError::not_enough_registers(span));
}
// Manually construct result string
let mut string = String::new();
let header = format!("[{}]\n", REGISTERS_VARIABLE_NAME);
string.push_str(&header);
// format: "token_id: u64 = 1u64;"
for (parameter, value) in register_values.into_iter().zip(return_values.into_iter()) {
let name = parameter.variable.name;
let type_ = parameter.type_;
let value = value.to_string();
let format = format!("{}: {} = {};\n", name, type_, value,);
string.push_str(&format);
}
let mut bytes: Vec<u8> = vec![];
bytes.extend_from_slice(string.as_bytes());
Ok(Self(bytes))
}
}
impl From<Vec<u8>> for OutputBytes {
fn from(bytes: Vec<u8>) -> Self {
Self(bytes)
}
}

View File

@ -0,0 +1,63 @@
//! The `program.out` file.
use crate::errors::OutputsFileError;
use std::{
fs::{self, File},
io::Write,
path::PathBuf,
};
pub static OUTPUTS_DIRECTORY_NAME: &str = "outputs/";
pub static OUTPUTS_FILE_EXTENSION: &str = ".out";
pub struct OutputsFile {
pub package_name: String,
}
impl OutputsFile {
pub fn new(package_name: &str) -> Self {
Self {
package_name: package_name.to_string(),
}
}
pub fn exists_at(&self, path: &PathBuf) -> bool {
let path = self.setup_file_path(path);
path.exists()
}
/// Reads the outputs from the given file path if it exists.
pub fn read_from(&self, path: &PathBuf) -> Result<String, OutputsFileError> {
let path = self.setup_file_path(path);
let inputs = fs::read_to_string(&path).map_err(|_| OutputsFileError::FileReadError(path.clone()))?;
Ok(inputs)
}
/// Writes output to a file.
pub fn write(&self, path: &PathBuf, bytes: &[u8]) -> Result<(), OutputsFileError> {
// create output file
let path = self.setup_file_path(path);
println!("setup {:?}", path);
let mut file = File::create(&path)?;
println!("created");
log::info!("Writing to output registers...");
Ok(file.write_all(bytes)?)
}
fn setup_file_path(&self, path: &PathBuf) -> PathBuf {
let mut path = path.to_owned();
if path.is_dir() {
if !path.ends_with(OUTPUTS_DIRECTORY_NAME) {
path.push(PathBuf::from(OUTPUTS_DIRECTORY_NAME));
}
path.push(PathBuf::from(format!(
"{}{}",
self.package_name, OUTPUTS_FILE_EXTENSION
)));
}
path
}
}

View File

@ -303,8 +303,8 @@ impl CondSelectGadget<Fq> for EdwardsGroupType {
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 first_gadget = first.allocated(cs.ns(|| "first"))?;
let second_gadget = second.allocated(cs.ns(|| "second"))?;
let result = EdwardsBlsGadget::conditionally_select(cs, cond, &first_gadget, &second_gadget)?;
Ok(EdwardsGroupType::Allocated(result))

View File

@ -1,3 +1,3 @@
function main(first: address, second: address) -> bool {
return first == second
function main(a: address, b: address, c: bool) {
assert_eq!(a == b, c);
}

View File

@ -1,38 +1,15 @@
use crate::{
boolean::{output_false, output_true},
get_error,
get_output,
parse_program,
EdwardsConstrainedValue,
EdwardsTestCompiler,
};
use leo_compiler::{Address, ConstrainedValue};
use crate::{assert_satisfied, expect_compiler_error, generate_main_inputs, parse_program};
use leo_types::InputValue;
use snarkos_dpc::base_dpc::instantiated::Components;
use snarkos_objects::AccountAddress;
use std::str::FromStr;
static TEST_ADDRESS_1: &'static str = "aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8";
static TEST_ADDRESS_2: &'static str = "aleo18qgam03qe483tdrcc3fkqwpp38ehff4a2xma6lu7hams6lfpgcpq3dq05r";
fn output_test_address(program: EdwardsTestCompiler, address: &str) {
let output = get_output(program);
let address_1 = AccountAddress::<Components>::from_str(address).unwrap();
assert_eq!(
EdwardsConstrainedValue::Return(vec![ConstrainedValue::Address(Address(Some(address_1)))]).to_string(),
output.to_string()
);
}
#[test]
fn test_valid() {
let bytes = include_bytes!("valid.leo");
let program = parse_program(bytes).unwrap();
let _output = get_output(program);
assert_satisfied(program)
}
#[test]
@ -40,7 +17,7 @@ fn test_invalid() {
let bytes = include_bytes!("invalid.leo");
let program = parse_program(bytes).unwrap();
let _output = get_error(program);
let _output = expect_compiler_error(program);
}
#[test]
@ -48,7 +25,7 @@ fn test_implicit_valid() {
let bytes = include_bytes!("implicit_valid.leo");
let program = parse_program(bytes).unwrap();
let _output = get_output(program);
assert_satisfied(program);
}
#[test]
@ -56,7 +33,7 @@ fn test_implicit_invalid() {
let bytes = include_bytes!("implicit_invalid.leo");
let program = parse_program(bytes).unwrap();
let _output = get_error(program);
let _output = expect_compiler_error(program);
}
#[test]
@ -64,7 +41,7 @@ fn test_assert_eq_pass() {
let bytes = include_bytes!("assert_eq_pass.leo");
let program = parse_program(bytes).unwrap();
let _output = get_output(program);
assert_satisfied(program);
}
#[test]
@ -72,61 +49,59 @@ fn test_assert_eq_fail() {
let bytes = include_bytes!("assert_eq_fail.leo");
let program = parse_program(bytes).unwrap();
let _output = get_error(program);
}
#[test]
fn test_input_pass() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Address(TEST_ADDRESS_1.to_string()))]);
let _output = get_output(program);
}
#[test]
fn test_input_fail_bool() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Boolean(true))]);
let _err = get_error(program);
let _output = expect_compiler_error(program);
}
#[test]
fn test_ternary() {
let bytes = include_bytes!("ternary.leo");
let mut program_1 = parse_program(bytes).unwrap();
let mut program_2 = program_1.clone();
let mut program = parse_program(bytes).unwrap();
program_1.set_inputs(vec![Some(InputValue::Boolean(true))]);
let main_inputs = generate_main_inputs(vec![
("s", Some(InputValue::Boolean(true))),
("c", Some(InputValue::Address(TEST_ADDRESS_1.to_string()))),
]);
output_test_address(program_1, TEST_ADDRESS_1);
program.set_main_inputs(main_inputs);
program_2.set_inputs(vec![Some(InputValue::Boolean(false))]);
assert_satisfied(program);
output_test_address(program_2, TEST_ADDRESS_2);
let mut program = parse_program(bytes).unwrap();
let main_inputs = generate_main_inputs(vec![
("s", Some(InputValue::Boolean(false))),
("c", Some(InputValue::Address(TEST_ADDRESS_2.to_string()))),
]);
program.set_main_inputs(main_inputs);
assert_satisfied(program);
}
#[test]
fn test_equal() {
let bytes = include_bytes!("equal.leo");
let mut program_1 = parse_program(bytes).unwrap();
let mut program_2 = program_1.clone();
let mut program = parse_program(bytes).unwrap();
program_1.set_inputs(vec![
Some(InputValue::Address(TEST_ADDRESS_1.to_string())),
Some(InputValue::Address(TEST_ADDRESS_1.to_string())),
let main_inputs = generate_main_inputs(vec![
("a", Some(InputValue::Address(TEST_ADDRESS_1.to_string()))),
("b", Some(InputValue::Address(TEST_ADDRESS_1.to_string()))),
("c", Some(InputValue::Boolean(true))),
]);
output_true(program_1);
program.set_main_inputs(main_inputs);
program_2.set_inputs(vec![
Some(InputValue::Address(TEST_ADDRESS_1.to_string())),
Some(InputValue::Address(TEST_ADDRESS_2.to_string())),
assert_satisfied(program);
let mut program = parse_program(bytes).unwrap();
let main_inputs = generate_main_inputs(vec![
("a", Some(InputValue::Address(TEST_ADDRESS_1.to_string()))),
("b", Some(InputValue::Address(TEST_ADDRESS_2.to_string()))),
("c", Some(InputValue::Boolean(false))),
]);
output_false(program_2);
program.set_main_inputs(main_inputs);
assert_satisfied(program);
}

View File

@ -1,6 +1,8 @@
function main(cond: bool) -> address {
let first = address(aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8);
let second = address(aleo18qgam03qe483tdrcc3fkqwpp38ehff4a2xma6lu7hams6lfpgcpq3dq05r);
function main(s: bool, c: address) {
let a = address(aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8);
let b = address(aleo18qgam03qe483tdrcc3fkqwpp38ehff4a2xma6lu7hams6lfpgcpq3dq05r);
return if cond ? first : second
let r = if s? a: b;
assert_eq!(r, c);
}

View File

@ -1,3 +1,3 @@
function main() -> u32[3] {
return [1u32; 3]
function main(a: u8[3]) {
assert_eq!(a, [1u8; 3]);
}

View File

@ -1,3 +1,3 @@
function main() -> u32[3] {
return [1u32, 1u32, 1u32]
function main(a: u8[3]) {
assert_eq!(a, [1u8, 1u8, 1u8]);
}

View File

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

View File

@ -0,0 +1,3 @@
function main() {
let a = [1u8, bool];
}

View File

@ -0,0 +1,2 @@
[registers]
r: u8[3] = [1u8, 1u8, 1u8];

View File

@ -0,0 +1,2 @@
[registers]
r: u8[3] = [0u8, 0u8, 0u8];

View File

@ -0,0 +1,2 @@
[main]
a: u8[3][2] = [[0; 3]; 2];

View File

@ -0,0 +1,2 @@
[main]
a: u8[3] = [1u8, 1u8, 1u8];

View File

@ -1,133 +1,95 @@
use crate::{
get_error,
get_output,
integers::fail_integer,
assert_satisfied,
expect_compiler_error,
get_outputs,
parse_program,
EdwardsConstrainedValue,
parse_program_with_inputs,
EdwardsTestCompiler,
};
use leo_compiler::{
errors::{CompilerError, FunctionError},
ConstrainedValue,
Integer,
};
use leo_inputs::types::{IntegerType, U32Type};
use leo_types::InputValue;
use snarkos_models::gadgets::utilities::uint::UInt32;
pub fn output_ones(program: EdwardsTestCompiler) {
let expected = include_bytes!("outputs_/registers_ones.out");
let actual = get_outputs(program);
// [1, 1, 1]
fn output_ones(program: EdwardsTestCompiler) {
let output = get_output(program);
assert_eq!(
EdwardsConstrainedValue::Return(vec![ConstrainedValue::Array(vec![
ConstrainedValue::Integer(
Integer::U32(UInt32::constant(1u32))
);
3
])])
.to_string(),
output.to_string()
);
assert!(expected.eq(actual.bytes().as_slice()));
}
// [[0, 0, 0],
// [0, 0, 0]]
fn output_multi(program: EdwardsTestCompiler) {
let output = get_output(program);
assert_eq!(
EdwardsConstrainedValue::Return(vec![ConstrainedValue::Array(vec![
ConstrainedValue::Array(
vec![ConstrainedValue::Integer(Integer::U32(UInt32::constant(0u32))); 3]
);
2
])])
.to_string(),
output.to_string()
)
pub fn output_zeros(program: EdwardsTestCompiler) {
let expected = include_bytes!("outputs_/registers_zeros.out");
let actual = get_outputs(program);
assert!(expected.eq(actual.bytes().as_slice()));
}
fn fail_array(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::Error(_string)) => {}
error => panic!("Expected function error, found {}", error),
}
}
// Registers
pub(crate) fn input_value_u32_one() -> InputValue {
InputValue::Integer(IntegerType::U32Type(U32Type {}), 1.to_string())
#[test]
fn test_registers() {
let program_bytes = include_bytes!("registers.leo");
let ones_input_bytes = include_bytes!("inputs/registers_ones.in");
let zeros_input_bytes = include_bytes!("inputs/registers_zeros.in");
// test ones input register => ones output register
let program = parse_program_with_inputs(program_bytes, ones_input_bytes).unwrap();
output_ones(program);
// test zeros input register => zeros output register
let program = parse_program_with_inputs(program_bytes, zeros_input_bytes).unwrap();
output_zeros(program);
}
// Expressions
#[test]
fn test_inline() {
let bytes = include_bytes!("inline.leo");
let program = parse_program(bytes).unwrap();
let program_bytes = include_bytes!("inline.leo");
let input_bytes = include_bytes!("inputs/three_ones.in");
let program = parse_program_with_inputs(program_bytes, input_bytes).unwrap();
output_ones(program);
assert_satisfied(program);
}
#[test]
fn test_inline_fail() {
let program_bytes = include_bytes!("inline.leo");
let program = parse_program(program_bytes).unwrap();
let _err = expect_compiler_error(program);
}
#[test]
fn test_initializer() {
let bytes = include_bytes!("initializer.leo");
let program = parse_program(bytes).unwrap();
let program_bytes = include_bytes!("initializer.leo");
let input_bytes = include_bytes!("inputs/three_ones.in");
let program = parse_program_with_inputs(program_bytes, input_bytes).unwrap();
output_ones(program);
assert_satisfied(program);
}
#[test]
fn test_spread() {
let bytes = include_bytes!("spread.leo");
let program = parse_program(bytes).unwrap();
let program_bytes = include_bytes!("spread.leo");
let input_bytes = include_bytes!("inputs/three_ones.in");
let program = parse_program_with_inputs(program_bytes, input_bytes).unwrap();
output_ones(program);
assert_satisfied(program);
}
#[test]
fn test_slice() {
let bytes = include_bytes!("slice.leo");
let program = parse_program(bytes).unwrap();
let program_bytes = include_bytes!("slice.leo");
let input_bytes = include_bytes!("inputs/three_ones.in");
let program = parse_program_with_inputs(program_bytes, input_bytes).unwrap();
output_ones(program);
assert_satisfied(program);
}
#[test]
fn test_multi() {
let bytes = include_bytes!("multi.leo");
let program = parse_program(bytes).unwrap();
let program_bytes = include_bytes!("multi.leo");
let program = parse_program(program_bytes).unwrap();
output_multi(program);
}
// Inputs
#[test]
fn test_input_array() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Array(vec![input_value_u32_one(); 3]))]);
output_ones(program)
}
#[test]
fn test_input_array_fail() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(input_value_u32_one())]);
fail_array(program);
}
#[test]
fn test_input_field_none() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![None]);
fail_integer(program)
assert_satisfied(program);
}

View File

@ -1,8 +1,8 @@
// Multidimensional array syntax in leo
function main() -> u32[3][2] {
const m = [[0u32, 0u32, 0u32], [0u32, 0u32, 0u32]]; // inline
function main() {
const a = [[0u32, 0u32, 0u32], [0u32, 0u32, 0u32]]; // inline
const m: u32[3][2] = [[0; 3]; 2]; // initializer
const b: u32[3][2] = [[0; 3]; 2]; // initializer
return m
assert_eq!(a, b);
}

View File

@ -0,0 +1,2 @@
[registers]
r: u8[3] = [1u8, 1u8, 1u8];

View File

@ -0,0 +1,2 @@
[registers]
r: u8[3] = [0u8, 0u8, 0u8];

View File

@ -0,0 +1,3 @@
function main(registers) -> u8[3] {
return registers.r
}

View File

@ -1,6 +1,6 @@
// `{from}..{to}` copies the elements of one array into another exclusively
function main() -> u32[3] {
let a = [1u32; 4];
function main(a: u8[3]) {
let b = [1u8; 4];
return a[0..3]
assert_eq!(a, b[0..3]);
}

View File

@ -1,6 +1,6 @@
// A spread operator `...` copies the elements of one array into another
function main() -> u32[3] {
let a = [1u32, 1u32];
function main(a: u8[3]) {
let b = [1u8, 1u8];
return [1u32, ...a]
assert_eq!(a, [1u8, ...b]);
}

View File

@ -1,8 +1,8 @@
// !(true && (false || true))
function main() -> bool {
function main() {
const a = true;
const b = false || a;
const c = !(true && b);
return c
assert_eq!(c, false);
}

View File

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

View File

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

View File

@ -1,3 +1,5 @@
function main() -> bool {
return false && false
function main() {
let a = false && false;
assert_eq!(a, false);
}

View File

@ -1,3 +1,5 @@
function main() -> bool {
return false || false
function main() {
let a = false || false;
assert_eq!(a, false);
}

View File

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

View File

@ -0,0 +1,2 @@
[registers]
r: bool = false;

View File

@ -0,0 +1,2 @@
[registers]
r: bool = true;

View File

@ -0,0 +1,3 @@
[main]
a: bool = true;
b: bool = false;

View File

@ -1,2 +1,3 @@
[main]
a: bool = true;
b: bool = true;

View File

@ -1,37 +1,30 @@
use crate::{get_error, get_output, parse_program, EdwardsConstrainedValue, EdwardsTestCompiler};
use leo_compiler::{
errors::{BooleanError, CompilerError, ExpressionError, FunctionError, StatementError},
ConstrainedValue,
use crate::{
assert_satisfied,
expect_compiler_error,
expect_synthesis_error,
get_outputs,
parse_program,
parse_program_with_inputs,
EdwardsTestCompiler,
};
use leo_types::InputValue;
use snarkos_models::gadgets::utilities::boolean::Boolean;
pub fn output_expected_boolean(program: EdwardsTestCompiler, boolean: bool) {
let output = get_output(program);
assert_eq!(
EdwardsConstrainedValue::Return(vec![ConstrainedValue::Boolean(Boolean::Constant(boolean))]).to_string(),
output.to_string()
);
}
use leo_compiler::errors::{BooleanError, CompilerError, ExpressionError, FunctionError, StatementError};
pub fn output_true(program: EdwardsTestCompiler) {
output_expected_boolean(program, true)
let expected = include_bytes!("outputs_/registers_true.out");
let actual = get_outputs(program);
assert_eq!(expected, actual.bytes().as_slice());
}
pub fn output_false(program: EdwardsTestCompiler) {
output_expected_boolean(program, false)
}
let expected = include_bytes!("outputs_/registers_false.out");
let actual = get_outputs(program);
fn fail_boolean(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::BooleanError(BooleanError::Error(_))) => {}
error => panic!("Expected boolean error, got {}", error),
}
assert_eq!(expected, actual.bytes().as_slice());
}
fn fail_boolean_statement(program: EdwardsTestCompiler) {
match get_error(program) {
match expect_compiler_error(program) {
CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError(
ExpressionError::BooleanError(BooleanError::Error(_)),
))) => {}
@ -40,41 +33,42 @@ fn fail_boolean_statement(program: EdwardsTestCompiler) {
}
#[test]
fn test_true() {
let bytes = include_bytes!("true.leo");
let program = parse_program(bytes).unwrap();
fn test_input_pass() {
let program_bytes = include_bytes!("assert_eq_input.leo");
let input_bytes = include_bytes!("inputs/true_true.in");
let program = parse_program_with_inputs(program_bytes, input_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_input_fail() {
let program_bytes = include_bytes!("assert_eq_input.leo");
let input_bytes = include_bytes!("inputs/true_false.in");
let program = parse_program_with_inputs(program_bytes, input_bytes).unwrap();
expect_synthesis_error(program);
}
#[test]
fn test_registers() {
let program_bytes = include_bytes!("output_register.leo");
let true_input_bytes = include_bytes!("inputs/registers_true.in");
let false_input_bytes = include_bytes!("inputs/registers_false.in");
// test true input register => true output register
let program = parse_program_with_inputs(program_bytes, true_input_bytes).unwrap();
output_true(program);
}
#[test]
fn test_false() {
let bytes = include_bytes!("false.leo");
let program = parse_program(bytes).unwrap();
// test false input register => false output register
let program = parse_program_with_inputs(program_bytes, false_input_bytes).unwrap();
output_false(program);
}
#[test]
fn test_input_bool_field() {
let bytes = include_bytes!("input_bool.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Field("1field".to_string()))]);
fail_boolean(program);
}
#[test]
fn test_input_bool_none() {
let bytes = include_bytes!("input_bool.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![None]);
fail_boolean(program);
}
// Boolean not !
#[test]
@ -82,7 +76,7 @@ fn test_not_true() {
let bytes = include_bytes!("not_true.leo");
let program = parse_program(bytes).unwrap();
output_false(program);
assert_satisfied(program);
}
#[test]
@ -90,7 +84,7 @@ fn test_not_false() {
let bytes = include_bytes!("not_false.leo");
let program = parse_program(bytes).unwrap();
output_true(program);
assert_satisfied(program);
}
#[test]
@ -98,7 +92,7 @@ fn test_not_u32() {
let bytes = include_bytes!("not_u32.leo");
let program = parse_program(bytes).unwrap();
fail_boolean_statement(program)
fail_boolean_statement(program);
}
// Boolean or ||
@ -108,7 +102,7 @@ fn test_true_or_true() {
let bytes = include_bytes!("true_or_true.leo");
let program = parse_program(bytes).unwrap();
output_true(program);
assert_satisfied(program);
}
#[test]
@ -116,7 +110,7 @@ fn test_true_or_false() {
let bytes = include_bytes!("true_or_false.leo");
let program = parse_program(bytes).unwrap();
output_true(program);
assert_satisfied(program);
}
#[test]
@ -124,7 +118,7 @@ fn test_false_or_false() {
let bytes = include_bytes!("false_or_false.leo");
let program = parse_program(bytes).unwrap();
output_false(program);
assert_satisfied(program);
}
#[test]
@ -142,7 +136,7 @@ fn test_true_and_true() {
let bytes = include_bytes!("true_and_true.leo");
let program = parse_program(bytes).unwrap();
output_true(program);
assert_satisfied(program);
}
#[test]
@ -150,7 +144,7 @@ fn test_true_and_false() {
let bytes = include_bytes!("true_and_false.leo");
let program = parse_program(bytes).unwrap();
output_false(program);
assert_satisfied(program);
}
#[test]
@ -158,7 +152,7 @@ fn test_false_and_false() {
let bytes = include_bytes!("false_and_false.leo");
let program = parse_program(bytes).unwrap();
output_false(program);
assert_satisfied(program);
}
#[test]
@ -176,5 +170,5 @@ fn test_all() {
let bytes = include_bytes!("all.leo");
let program = parse_program(bytes).unwrap();
output_false(program);
assert_satisfied(program);
}

View File

@ -1,3 +1,3 @@
function main() -> bool {
return !false
function main() {
assert_eq!(!false, true);
}

View File

@ -1,3 +1,3 @@
function main() -> bool {
return !true
function main() {
assert_eq!(!true, false);
}

View File

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

View File

@ -0,0 +1,3 @@
function main(registers) -> bool {
return registers.r
}

View File

@ -0,0 +1,2 @@
[registers]
r: bool = false;

View File

@ -0,0 +1,2 @@
[registers]
r: bool = true;

View File

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

View File

@ -1,3 +1,5 @@
function main() -> bool {
return true && false
function main() {
let a = true && false;
assert_eq!(a, false);
}

View File

@ -1,3 +1,5 @@
function main() -> bool {
return true && true
function main() {
let a = true && true;
assert_eq!(a, true);
}

View File

@ -1,3 +1,3 @@
function main() -> bool {
return true && 1u32
function main() {
let a = true && 1u32;
}

View File

@ -1,3 +1,5 @@
function main() -> bool {
return true || false
function main() {
let a = true || false;
assert_eq!(a, true);
}

View File

@ -1,3 +1,5 @@
function main() -> bool {
return true || true
function main() {
let a = true || true;
assert_eq!(a, true);
}

View File

@ -1,3 +1,3 @@
function main() -> bool {
return true || 1u32
function main() {
let a = true || 1u32;
}

View File

@ -2,6 +2,6 @@ circuit Foo {
x: u32
}
function main() -> Foo {
return Foo { x: 1u32 }
function main() {
let a = Foo { x: 1u32 };
}

View File

@ -3,5 +3,5 @@ circuit Foo {
}
function main() {
let c = Foo { y: 0u32 };
let a = Foo { y: 0u32 };
}

View File

@ -1,3 +1,3 @@
function main() {
let c = Foo { };
let a = Foo { };
}

View File

@ -2,8 +2,8 @@ circuit Foo {
x: u32,
}
function main() -> u32 {
let c = Foo { x: 1u32 };
function main() {
let a = Foo { x: 1u32 };
return c.x
assert_eq!(a.x, 1u32);
}

View File

@ -2,11 +2,14 @@ circuit Foo {
foo: u32,
static function bar() -> u32 {
return 0
return 1u32
}
}
function main() -> u32 {
let f = Foo { foo: 1 };
return f.foo + Foo::bar()
function main() {
let a = Foo { foo: 1 };
let b = a.foo + Foo::bar();
assert_eq!(b, 2u32);
}

View File

@ -2,8 +2,8 @@ circuit Foo {
x: u32
}
function main() -> u32 {
let c = Foo { x: 1u32 };
function main() {
let a = Foo { x: 1u32 };
return c.y
let err = a.y;
}

View File

@ -4,7 +4,8 @@ circuit Foo {
}
}
function main() -> u32 {
let c = Foo { };
return c.echo(1u32)
function main() {
let a = Foo { };
assert_eq!(a.echo(1u32), 1u32);
}

View File

@ -4,7 +4,7 @@ circuit Foo {
}
}
function main() -> u32 {
let c = Foo { };
return c.echoed(1u32)
function main() {
let a = Foo { };
let err = a.echoed(1u32);
}

View File

@ -4,7 +4,7 @@ circuit Foo {
}
}
function main() -> u32 {
let c = Foo { };
return c.echo(1u32) // echo is a static function and must be accessed using `::`
function main() {
let a = Foo { };
let err = a.echo(1u32); // echo is a static function and must be accessed using `::`
}

View File

@ -10,8 +10,9 @@ circuit Foo {
}
}
function main() -> u32 {
let f = Foo { x: 1u32 };
function main() {
let a = Foo { x: 1u32 };
let b = a.call_add_x(1u32);
return f.call_add_x(1u32)
assert_eq!(b, 2u32);
}

View File

@ -4,6 +4,8 @@ circuit Foo {
}
}
function main() -> u32 {
return Foo::echo(1u32)
function main() {
let a = Foo::echo(1u32);
assert_eq!(a, 1u32);
}

View File

@ -4,6 +4,6 @@ circuit Foo {
}
}
function main() -> u32 {
return Foo::echo(1u32) // echo is a non-static function and must be accessed using `.`
function main() {
let err = Foo::echo(1u32); // echo is a non-static function and must be accessed using `.`
}

View File

@ -4,6 +4,6 @@ circuit Foo {
}
}
function main() -> u32 {
return Foo::echoed(1u32)
function main() {
let err = Foo::echoed(1u32);
}

View File

@ -1,55 +1,8 @@
use crate::{
get_error,
get_output,
integers::u32::{output_number, output_one},
parse_program,
EdwardsConstrainedValue,
EdwardsTestCompiler,
};
use leo_compiler::{
errors::{CompilerError, ExpressionError, FunctionError, StatementError},
ConstrainedCircuitMember,
ConstrainedValue,
Integer,
};
use leo_types::{Expression, Function, Identifier, Span, Statement, Type};
use snarkos_models::gadgets::utilities::uint::UInt32;
// Foo { x: 1u32 }
fn output_circuit(program: EdwardsTestCompiler) {
let output = get_output(program);
assert_eq!(
EdwardsConstrainedValue::Return(vec![ConstrainedValue::CircuitExpression(
Identifier {
name: "Foo".to_string(),
span: Span {
text: "".to_string(),
line: 0,
start: 0,
end: 0
}
},
vec![ConstrainedCircuitMember(
Identifier {
name: "x".to_string(),
span: Span {
text: "".to_string(),
line: 0,
start: 0,
end: 0
}
},
ConstrainedValue::Integer(Integer::U32(UInt32::constant(1u32)))
)]
)])
.to_string(),
output.to_string()
);
}
use crate::{assert_satisfied, expect_compiler_error, parse_program, EdwardsTestCompiler};
use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, StatementError};
fn expect_fail(program: EdwardsTestCompiler) {
match get_error(program) {
match expect_compiler_error(program) {
CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError(
ExpressionError::Error(_string),
))) => {}
@ -64,7 +17,7 @@ fn test_inline() {
let bytes = include_bytes!("inline.leo");
let program = parse_program(bytes).unwrap();
output_circuit(program);
assert_satisfied(program);
}
#[test]
@ -72,7 +25,7 @@ fn test_inline_fail() {
let bytes = include_bytes!("inline_fail.leo");
let program = parse_program(bytes).unwrap();
expect_fail(program)
expect_fail(program);
}
#[test]
@ -80,12 +33,7 @@ fn test_inline_undefined() {
let bytes = include_bytes!("inline_undefined.leo");
let program = parse_program(bytes).unwrap();
match get_error(program) {
CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError(
ExpressionError::Error(_),
))) => {}
error => panic!("Expected undefined circuit error, got {}", error),
}
expect_fail(program);
}
// Members
@ -95,7 +43,7 @@ fn test_member_field() {
let bytes = include_bytes!("member_field.leo");
let program = parse_program(bytes).unwrap();
output_one(program);
assert_satisfied(program);
}
#[test]
@ -111,7 +59,7 @@ fn test_member_field_and_function() {
let bytes = include_bytes!("member_field_and_function.leo");
let program = parse_program(bytes).unwrap();
output_one(program);
assert_satisfied(program);
}
#[test]
@ -119,7 +67,7 @@ fn test_member_function() {
let bytes = include_bytes!("member_function.leo");
let program = parse_program(bytes).unwrap();
output_one(program);
assert_satisfied(program);
}
#[test]
@ -143,7 +91,7 @@ fn test_member_function_nested() {
let bytes = include_bytes!("member_function_nested.leo");
let program = parse_program(bytes).unwrap();
output_number(program, 2u32);
assert_satisfied(program);
}
#[test]
@ -151,15 +99,7 @@ fn test_member_static_function() {
let bytes = include_bytes!("member_static_function.leo");
let program = parse_program(bytes).unwrap();
output_one(program);
}
#[test]
fn test_member_static_function_undefined() {
let bytes = include_bytes!("member_static_function_undefined.leo");
let program = parse_program(bytes).unwrap();
expect_fail(program)
assert_satisfied(program);
}
#[test]
@ -170,135 +110,45 @@ fn test_member_static_function_invalid() {
expect_fail(program)
}
#[test]
fn test_member_static_function_undefined() {
let bytes = include_bytes!("member_static_function_undefined.leo");
let program = parse_program(bytes).unwrap();
expect_fail(program)
}
// Self
#[test]
fn test_self_member() {
fn test_self_member_pass() {
let bytes = include_bytes!("self_member.leo");
let program = parse_program(bytes).unwrap();
output_one(program);
assert_satisfied(program);
}
#[test]
fn test_self_no_member_fail() {
let bytes = include_bytes!("self_no_member_fail.leo");
fn test_self_member_invalid() {
let bytes = include_bytes!("self_member_invalid.leo");
let program = parse_program(bytes).unwrap();
let _err = get_error(program);
let _err = expect_compiler_error(program);
}
#[test]
fn test_self_member_fail() {
let bytes = include_bytes!("self_member_fail.leo");
fn test_self_member_undefined() {
let bytes = include_bytes!("self_member_undefined.leo");
let program = parse_program(bytes).unwrap();
let _err = get_error(program);
}
#[test]
fn test_self_circuit() {
let bytes = include_bytes!("self_circuit.leo");
let program = parse_program(bytes).unwrap();
let output = get_output(program);
// circuit Foo {
// static function new() -> Self {
// return Self { }
// }
// }
assert_eq!(
EdwardsConstrainedValue::Return(vec![ConstrainedValue::CircuitExpression(
Identifier {
name: "Foo".to_string(),
span: Span {
text: "".to_string(),
line: 0,
start: 0,
end: 0
}
},
vec![ConstrainedCircuitMember(
Identifier {
name: "new".to_string(),
span: Span {
text: "".to_string(),
line: 0,
start: 0,
end: 0
}
},
ConstrainedValue::Static(Box::new(ConstrainedValue::Function(
Some(Identifier {
name: "new".to_string(),
span: Span {
text: "".to_string(),
line: 0,
start: 0,
end: 0
}
}),
Function {
function_name: Identifier {
name: "new".to_string(),
span: Span {
text: "".to_string(),
line: 0,
start: 0,
end: 0
}
},
inputs: vec![],
returns: vec![Type::SelfType],
statements: vec![Statement::Return(
vec![Expression::Circuit(
Identifier {
name: "Self".to_string(),
span: Span {
text: "".to_string(),
line: 0,
start: 0,
end: 0
}
},
vec![],
Span {
text: "".to_string(),
line: 0,
start: 0,
end: 0
}
)],
Span {
text: "".to_string(),
line: 0,
start: 0,
end: 0
}
)],
span: Span {
text: "".to_string(),
line: 0,
start: 0,
end: 0
}
}
)))
)]
)])
.to_string(),
output.to_string()
);
let _err = expect_compiler_error(program);
}
// All
#[test]
fn test_pedersen_mock() {
use crate::integers::u32::output_zero;
let bytes = include_bytes!("pedersen_mock.leo");
let program = parse_program(bytes).unwrap();
output_zero(program);
assert_satisfied(program);
}

View File

@ -16,9 +16,10 @@ circuit PedersenHash {
}
// The 'pedersen_hash' main function.
function main() -> u32 {
function main() {
let parameters = [0u32; 512];
let pedersen = PedersenHash::new(parameters);
let input: bool[512] = [true; 512];
return pedersen.hash(input)
assert_eq!(pedersen.hash(input), 0u32);
}

View File

@ -4,6 +4,6 @@ circuit Foo {
}
}
function main() -> Foo {
return Foo::new()
function main() {
let a = Foo::new();
}

View File

@ -6,7 +6,9 @@ circuit Foo {
}
}
function main() -> u32 {
let foo = Foo { f: 1u32 };
return foo.bar()
function main() {
let a = Foo { f: 1u32 };
let b = a.bar();
assert_eq!(b, 1u32);
}

View File

@ -8,5 +8,5 @@ circuit Foo {
function main() -> u32 {
let foo = Foo { f: 1u32 };
return foo.bar()
let err = foo.bar();
}

View File

@ -4,7 +4,7 @@ circuit Foo {
}
}
function main() -> u32 {
function main() {
let foo = Foo { };
return foo.bar()
let err = foo.bar();
}

View File

@ -0,0 +1 @@
[registers]

View File

@ -1,3 +1,3 @@
function main(a: field, b: field) -> field {
return a + b
function main(a: field, b: field, c: field) {
assert_eq!(a + b, c);
}

View File

@ -1,3 +1,3 @@
function main(a: field, b: field) -> field {
return a / b
function main(a: field, b: field, c: field) {
assert_eq!(a / b, c);
}

View File

@ -1,3 +1,3 @@
function main(a: field, b: field) -> bool {
return a == b
function main(a: field, b: field, c: bool) {
assert_eq!(a == b, c);
}

View File

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

View File

@ -0,0 +1,2 @@
[registers]
r: field = 1;

View File

@ -0,0 +1,2 @@
[registers]
r: field = 0;

View File

@ -1,112 +1,26 @@
use crate::{
boolean::{output_expected_boolean, output_true},
get_error,
get_output,
parse_program,
EdwardsConstrainedValue,
EdwardsTestCompiler,
};
use leo_compiler::{
errors::{CompilerError, FieldError, FunctionError},
ConstrainedValue,
FieldType,
};
use crate::{assert_satisfied, expect_synthesis_error, generate_main_inputs, parse_program};
use leo_types::InputValue;
use snarkos_curves::edwards_bls12::Fq;
use snarkos_utilities::bytes::ToBytes;
use num_bigint::BigUint;
use rand::{Rng, SeedableRng};
use rand_xorshift::XorShiftRng;
use snarkos_curves::edwards_bls12::Fq;
use snarkos_gadgets::curves::edwards_bls12::FqGadget;
use snarkos_models::{
curves::{One, PrimeField, Zero},
gadgets::{
curves::field::FieldGadget,
r1cs::{ConstraintSystem, TestConstraintSystem},
},
};
use snarkos_utilities::{biginteger::BigInteger256, bytes::ToBytes};
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()
);
}
// Helper function to convert field element into decimal base 10 string
pub fn field_to_decimal_string(f: Fq) -> String {
// write field to buffer
fn output_expected_allocated(program: EdwardsTestCompiler, expected: FqGadget) {
let output = get_output(program);
let mut buf = Vec::new();
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"),
}
}
f.write(&mut buf).unwrap();
fn output_zero(program: EdwardsTestCompiler) {
output_expected_constant(program, Fq::zero())
}
// convert to big integer
fn output_one(program: EdwardsTestCompiler) {
output_expected_constant(program, Fq::one())
}
let f_bigint = BigUint::from_bytes_le(&buf);
fn fail_field(program: EdwardsTestCompiler) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::FieldError(FieldError::Error(_string))) => {}
error => panic!("Expected invalid field error, got {}", error),
}
}
#[test]
fn test_zero() {
let bytes = include_bytes!("zero.leo");
let program = parse_program(bytes).unwrap();
output_zero(program);
}
#[test]
fn test_one() {
let bytes = include_bytes!("one.leo");
let program = parse_program(bytes).unwrap();
output_one(program);
}
#[test]
fn test_input_pass() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).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 bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Boolean(true))]);
fail_field(program);
}
#[test]
fn test_input_fail_none() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![None]);
fail_field(program);
f_bigint.to_str_radix(10)
}
#[test]
@ -116,32 +30,26 @@ fn test_add() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 {
let r1: Fq = rng.gen();
let r2: Fq = rng.gen();
let a: Fq = rng.gen();
let b: Fq = rng.gen();
let c = a.add(&b);
let mut r1_buf = Vec::new();
let mut r2_buf = Vec::new();
r1.write(&mut r1_buf).unwrap();
r2.write(&mut r2_buf).unwrap();
let r1_bigint = BigUint::from_bytes_le(&r1_buf);
let r2_bigint = BigUint::from_bytes_le(&r2_buf);
let sum = r1.add(&r2);
let cs = TestConstraintSystem::<Fq>::new();
let sum_allocated = FqGadget::from(cs, &sum);
let a_string = field_to_decimal_string(a);
let b_string = field_to_decimal_string(b);
let c_string = field_to_decimal_string(c);
let bytes = include_bytes!("add.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
let main_inputs = generate_main_inputs(vec![
("a", Some(InputValue::Field(a_string))),
("b", Some(InputValue::Field(b_string))),
("c", Some(InputValue::Field(c_string))),
]);
output_expected_allocated(program, sum_allocated);
program.set_main_inputs(main_inputs);
assert_satisfied(program)
}
}
@ -152,68 +60,25 @@ fn test_sub() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 {
let r1: Fq = rng.gen();
let r2: Fq = rng.gen();
let a: Fq = rng.gen();
let b: Fq = rng.gen();
let c = a.sub(&b);
let mut r1_buf = Vec::new();
let mut r2_buf = Vec::new();
r1.write(&mut r1_buf).unwrap();
r2.write(&mut r2_buf).unwrap();
let r1_bigint = BigUint::from_bytes_le(&r1_buf);
let r2_bigint = BigUint::from_bytes_le(&r2_buf);
let difference = r1.sub(&r2);
let cs = TestConstraintSystem::<Fq>::new();
let difference_allocated = FqGadget::from(cs, &difference);
let a_string = field_to_decimal_string(a);
let b_string = field_to_decimal_string(b);
let c_string = field_to_decimal_string(c);
let bytes = include_bytes!("sub.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
let main_inputs = generate_main_inputs(vec![
("a", Some(InputValue::Field(a_string))),
("b", Some(InputValue::Field(b_string))),
("c", Some(InputValue::Field(c_string))),
]);
program.set_main_inputs(main_inputs);
output_expected_allocated(program, difference_allocated);
}
}
#[test]
fn test_mul() {
use std::ops::Mul;
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 {
let r1: Fq = rng.gen();
let r2: Fq = rng.gen();
let mut r1_buf = Vec::new();
let mut r2_buf = Vec::new();
r1.write(&mut r1_buf).unwrap();
r2.write(&mut r2_buf).unwrap();
let r1_bigint = BigUint::from_bytes_le(&r1_buf);
let r2_bigint = BigUint::from_bytes_le(&r2_buf);
let product = r1.mul(&r2);
let cs = TestConstraintSystem::<Fq>::new();
let product_allocated = FqGadget::from(cs, &product);
let bytes = include_bytes!("mul.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
]);
output_expected_allocated(program, product_allocated);
assert_satisfied(program)
}
}
@ -224,32 +89,55 @@ fn test_div() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 {
let r1: Fq = rng.gen();
let r2: Fq = rng.gen();
let a: Fq = rng.gen();
let b: Fq = rng.gen();
let c = a.div(&b);
let mut r1_buf = Vec::new();
let mut r2_buf = Vec::new();
r1.write(&mut r1_buf).unwrap();
r2.write(&mut r2_buf).unwrap();
let r1_bigint = BigUint::from_bytes_le(&r1_buf);
let r2_bigint = BigUint::from_bytes_le(&r2_buf);
let quotient = r1.div(&r2);
let cs = TestConstraintSystem::<Fq>::new();
let quotient_allocated = FqGadget::from(cs, &quotient);
let a_string = field_to_decimal_string(a);
let b_string = field_to_decimal_string(b);
let c_string = field_to_decimal_string(c);
let bytes = include_bytes!("div.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
let main_inputs = generate_main_inputs(vec![
("a", Some(InputValue::Field(a_string))),
("b", Some(InputValue::Field(b_string))),
("c", Some(InputValue::Field(c_string))),
]);
program.set_main_inputs(main_inputs);
assert_satisfied(program)
}
}
#[test]
fn test_mul() {
use std::ops::Mul;
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 {
let a: Fq = rng.gen();
let b: Fq = rng.gen();
let c = a.mul(&b);
let a_string = field_to_decimal_string(a);
let b_string = field_to_decimal_string(b);
let c_string = field_to_decimal_string(c);
let bytes = include_bytes!("mul.leo");
let mut program = parse_program(bytes).unwrap();
let main_inputs = generate_main_inputs(vec![
("a", Some(InputValue::Field(a_string))),
("b", Some(InputValue::Field(b_string))),
("c", Some(InputValue::Field(c_string))),
]);
output_expected_allocated(program, quotient_allocated);
program.set_main_inputs(main_inputs);
assert_satisfied(program)
}
}
@ -258,42 +146,42 @@ fn test_eq() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 {
let r1: Fq = rng.gen();
let r2: Fq = rng.gen();
let a: Fq = rng.gen();
let b: Fq = rng.gen();
let mut r1_buf = Vec::new();
let mut r2_buf = Vec::new();
r1.write(&mut r1_buf).unwrap();
r2.write(&mut r2_buf).unwrap();
let r1_bigint = BigUint::from_bytes_le(&r1_buf);
let r2_bigint = BigUint::from_bytes_le(&r2_buf);
let a_string = field_to_decimal_string(a);
let b_string = field_to_decimal_string(b);
// test equal
let bytes = include_bytes!("eq.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
let main_inputs = generate_main_inputs(vec![
("a", Some(InputValue::Field(a_string.clone()))),
("b", Some(InputValue::Field(a_string.clone()))),
("c", Some(InputValue::Boolean(true))),
]);
output_true(program);
program.set_main_inputs(main_inputs);
assert_satisfied(program);
// test not equal
let result = r1.eq(&r2);
let c = a.eq(&b);
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
let main_inputs = generate_main_inputs(vec![
("a", Some(InputValue::Field(a_string))),
("b", Some(InputValue::Field(b_string))),
("c", Some(InputValue::Boolean(c))),
]);
output_expected_boolean(program, result)
program.set_main_inputs(main_inputs);
assert_satisfied(program);
}
}
@ -302,20 +190,21 @@ fn test_assert_eq_pass() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 {
let r1: Fq = rng.gen();
let mut r1_buf = Vec::new();
r1.write(&mut r1_buf).unwrap();
let r1_bigint = BigUint::from_bytes_le(&r1_buf);
let a: Fq = rng.gen();
let a_string = field_to_decimal_string(a);
let bytes = include_bytes!("assert_eq.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
let main_inputs = generate_main_inputs(vec![
("a", Some(InputValue::Field(a_string.clone()))),
("b", Some(InputValue::Field(a_string))),
]);
let _ = get_output(program);
program.set_main_inputs(main_inputs);
assert_satisfied(program);
}
}
@ -324,68 +213,98 @@ fn test_assert_eq_fail() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 {
let r1: Fq = rng.gen();
let r2: Fq = rng.gen();
let a: Fq = rng.gen();
let b: Fq = rng.gen();
let mut r1_buf = Vec::new();
let mut r2_buf = Vec::new();
r1.write(&mut r1_buf).unwrap();
r2.write(&mut r2_buf).unwrap();
let r1_bigint = BigUint::from_bytes_le(&r1_buf);
let r2_bigint = BigUint::from_bytes_le(&r2_buf);
if r1 == r2 {
if a == b {
continue;
}
let a_string = field_to_decimal_string(a);
let b_string = field_to_decimal_string(b);
let bytes = include_bytes!("assert_eq.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
let main_inputs = generate_main_inputs(vec![
("a", Some(InputValue::Field(a_string))),
("b", Some(InputValue::Field(b_string))),
]);
let mut cs = TestConstraintSystem::<Fq>::new();
let _ = program.compile_constraints(&mut cs).unwrap();
assert!(!cs.is_satisfied());
program.set_main_inputs(main_inputs);
expect_synthesis_error(program);
}
}
#[test]
fn test_ternary() {
let r1: u64 = rand::random();
let r2: u64 = rand::random();
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
let b1 = BigInteger256::from(r1);
let b2 = BigInteger256::from(r2);
let a: Fq = rng.gen();
let b: Fq = rng.gen();
let f1: Fq = Fq::from_repr(b1).unwrap();
let f2: Fq = Fq::from_repr(b2).unwrap();
let mut cs = TestConstraintSystem::<Fq>::new();
let g1 = FqGadget::from(cs.ns(|| "g1"), &f1);
let g2 = FqGadget::from(cs.ns(|| "g2"), &f2);
let a_string = field_to_decimal_string(a);
let b_string = field_to_decimal_string(b);
let bytes = include_bytes!("ternary.leo");
let mut program_1 = parse_program(bytes).unwrap();
let mut program_2 = program_1.clone();
let mut program = parse_program(bytes).unwrap();
// true -> field 1
program_1.set_inputs(vec![
Some(InputValue::Boolean(true)),
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r2.to_string())),
// true -> field a
let main_inputs = generate_main_inputs(vec![
("s", Some(InputValue::Boolean(true))),
("a", Some(InputValue::Field(a_string.clone()))),
("b", Some(InputValue::Field(b_string.clone()))),
("c", Some(InputValue::Field(a_string.clone()))),
]);
output_expected_allocated(program_1, g1);
program.set_main_inputs(main_inputs);
// false -> field 2
program_2.set_inputs(vec![
Some(InputValue::Boolean(false)),
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r2.to_string())),
assert_satisfied(program);
let mut program = parse_program(bytes).unwrap();
// false -> field b
let main_inputs = generate_main_inputs(vec![
("s", Some(InputValue::Boolean(false))),
("a", Some(InputValue::Field(a_string))),
("b", Some(InputValue::Field(b_string.clone()))),
("c", Some(InputValue::Field(b_string))),
]);
output_expected_allocated(program_2, g2);
program.set_main_inputs(main_inputs);
assert_satisfied(program);
}
//
// pub fn output_one(program: EdwardsTestCompiler) {
// let expected = include_bytes!("outputs_/register_one.out");
// let actual = get_outputs(program);
//
// assert_eq!(expected, actual.bytes().as_slice());
// }
//
// pub fn output_zero(program: EdwardsTestCompiler) {
// let expected = include_bytes!("outputs_/register_zero.out");
// let actual = get_outputs(program);
//
// assert_eq!(expected, actual.bytes().as_slice());
// }
//
// #[test]
// fn test_registers() {
// let program_bytes = include_bytes!("output_register.leo");
// let one_input_bytes = include_bytes!("inputs/register_one.in");
// let zero_input_bytes = include_bytes!("inputs/register_zero.in");
//
// // test 1field input register => 1field output register
// let program = parse_program_with_inputs(program_bytes, one_input_bytes).unwrap();
//
// output_one(program);
//
// // test 0field input register => 0field output register
// let program = parse_program_with_inputs(program_bytes, zero_input_bytes).unwrap();
//
// output_zero(program);
// }

View File

@ -1,3 +1,3 @@
function main(a: field, b: field) -> field {
return a * b
function main(a: field, b: field, c: field) {
assert_eq!(a * b, c);
}

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