mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-24 18:52:58 +03:00
Merge pull request #122 from AleoHQ/feature/runtime-state
Feature/runtime state
This commit is contained in:
commit
17e2adcdb4
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -609,6 +609,7 @@ dependencies = [
|
||||
"pest",
|
||||
"rand",
|
||||
"rand_xorshift",
|
||||
"serde",
|
||||
"sha2",
|
||||
"snarkos-curves",
|
||||
"snarkos-dpc",
|
||||
|
@ -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())]
|
||||
|
17
ast/src/functions/inputs/input.rs
Normal file
17
ast/src/functions/inputs/input.rs
Normal 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>),
|
||||
}
|
17
ast/src/functions/inputs/mod.rs
Normal file
17
ast/src/functions/inputs/mod.rs
Normal 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::*;
|
13
ast/src/functions/inputs/record.rs
Normal file
13
ast/src/functions/inputs/record.rs
Normal 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>,
|
||||
}
|
13
ast/src/functions/inputs/registers.rs
Normal file
13
ast/src/functions/inputs/registers.rs
Normal 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>,
|
||||
}
|
13
ast/src/functions/inputs/state.rs
Normal file
13
ast/src/functions/inputs/state.rs
Normal 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>,
|
||||
}
|
13
ast/src/functions/inputs/state_leaf.rs
Normal file
13
ast/src/functions/inputs/state_leaf.rs
Normal 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>,
|
||||
}
|
@ -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::*;
|
||||
|
@ -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 }
|
||||
|
@ -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" }
|
@ -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(())
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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::*;
|
||||
|
||||
|
33
compiler/src/errors/output_bytes.rs
Normal file
33
compiler/src/errors/output_bytes.rs
Normal 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)
|
||||
}
|
||||
}
|
22
compiler/src/errors/output_file.rs
Normal file
22
compiler/src/errors/output_file.rs
Normal 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))
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
@ -8,3 +8,6 @@ pub use self::input::*;
|
||||
|
||||
pub mod main_input;
|
||||
pub use self::main_input::*;
|
||||
|
||||
pub mod section;
|
||||
pub use self::section::*;
|
||||
|
37
compiler/src/function/input/section.rs
Normal file
37
compiler/src/function/input/section.rs
Normal 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))
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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::*;
|
||||
|
||||
|
5
compiler/src/output/mod.rs
Normal file
5
compiler/src/output/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
pub mod output_file;
|
||||
pub use self::output_file::*;
|
||||
|
||||
pub mod output_bytes;
|
||||
pub use self::output_bytes::*;
|
69
compiler/src/output/output_bytes.rs
Normal file
69
compiler/src/output/output_bytes.rs
Normal 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)
|
||||
}
|
||||
}
|
63
compiler/src/output/output_file.rs
Normal file
63
compiler/src/output/output_file.rs
Normal 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
|
||||
}
|
||||
}
|
@ -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))
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> u32[3] {
|
||||
return [1u32; 3]
|
||||
function main(a: u8[3]) {
|
||||
assert_eq!(a, [1u8; 3]);
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> u32[3] {
|
||||
return [1u32, 1u32, 1u32]
|
||||
function main(a: u8[3]) {
|
||||
assert_eq!(a, [1u8, 1u8, 1u8]);
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
function main(arr: u32[3]) -> u32[3] {
|
||||
return arr
|
||||
}
|
3
compiler/tests/array/inputs/inline_fail.leo
Normal file
3
compiler/tests/array/inputs/inline_fail.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main() {
|
||||
let a = [1u8, bool];
|
||||
}
|
2
compiler/tests/array/inputs/registers_ones.in
Normal file
2
compiler/tests/array/inputs/registers_ones.in
Normal file
@ -0,0 +1,2 @@
|
||||
[registers]
|
||||
r: u8[3] = [1u8, 1u8, 1u8];
|
2
compiler/tests/array/inputs/registers_zeros.in
Normal file
2
compiler/tests/array/inputs/registers_zeros.in
Normal file
@ -0,0 +1,2 @@
|
||||
[registers]
|
||||
r: u8[3] = [0u8, 0u8, 0u8];
|
2
compiler/tests/array/inputs/six_zeros.in
Normal file
2
compiler/tests/array/inputs/six_zeros.in
Normal file
@ -0,0 +1,2 @@
|
||||
[main]
|
||||
a: u8[3][2] = [[0; 3]; 2];
|
2
compiler/tests/array/inputs/three_ones.in
Normal file
2
compiler/tests/array/inputs/three_ones.in
Normal file
@ -0,0 +1,2 @@
|
||||
[main]
|
||||
a: u8[3] = [1u8, 1u8, 1u8];
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
2
compiler/tests/array/outputs_/registers_ones.out
Normal file
2
compiler/tests/array/outputs_/registers_ones.out
Normal file
@ -0,0 +1,2 @@
|
||||
[registers]
|
||||
r: u8[3] = [1u8, 1u8, 1u8];
|
2
compiler/tests/array/outputs_/registers_zeros.out
Normal file
2
compiler/tests/array/outputs_/registers_zeros.out
Normal file
@ -0,0 +1,2 @@
|
||||
[registers]
|
||||
r: u8[3] = [0u8, 0u8, 0u8];
|
3
compiler/tests/array/registers.leo
Normal file
3
compiler/tests/array/registers.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main(registers) -> u8[3] {
|
||||
return registers.r
|
||||
}
|
@ -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]);
|
||||
}
|
||||
|
@ -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]);
|
||||
}
|
@ -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);
|
||||
}
|
3
compiler/tests/boolean/assert_eq_input.leo
Normal file
3
compiler/tests/boolean/assert_eq_input.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main(a: bool, b: bool) {
|
||||
assert_eq!(a, b);
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
function main() -> bool {
|
||||
return false
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
function main() -> bool {
|
||||
return false && false
|
||||
function main() {
|
||||
let a = false && false;
|
||||
|
||||
assert_eq!(a, false);
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
function main() -> bool {
|
||||
return false || false
|
||||
function main() {
|
||||
let a = false || false;
|
||||
|
||||
assert_eq!(a, false);
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
function main(b: bool) -> bool{
|
||||
return b
|
||||
}
|
2
compiler/tests/boolean/inputs/registers_false.in
Normal file
2
compiler/tests/boolean/inputs/registers_false.in
Normal file
@ -0,0 +1,2 @@
|
||||
[registers]
|
||||
r: bool = false;
|
2
compiler/tests/boolean/inputs/registers_true.in
Normal file
2
compiler/tests/boolean/inputs/registers_true.in
Normal file
@ -0,0 +1,2 @@
|
||||
[registers]
|
||||
r: bool = true;
|
3
compiler/tests/boolean/inputs/true_false.in
Normal file
3
compiler/tests/boolean/inputs/true_false.in
Normal file
@ -0,0 +1,3 @@
|
||||
[main]
|
||||
a: bool = true;
|
||||
b: bool = false;
|
@ -1,2 +1,3 @@
|
||||
[main]
|
||||
a: bool = true;
|
||||
b: bool = true;
|
@ -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);
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return !false
|
||||
function main() {
|
||||
assert_eq!(!false, true);
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return !true
|
||||
function main() {
|
||||
assert_eq!(!true, false);
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return !1u32
|
||||
assert_eq!(!1u32, 0u32);
|
||||
}
|
3
compiler/tests/boolean/output_register.leo
Normal file
3
compiler/tests/boolean/output_register.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main(registers) -> bool {
|
||||
return registers.r
|
||||
}
|
2
compiler/tests/boolean/outputs_/registers_false.out
Normal file
2
compiler/tests/boolean/outputs_/registers_false.out
Normal file
@ -0,0 +1,2 @@
|
||||
[registers]
|
||||
r: bool = false;
|
2
compiler/tests/boolean/outputs_/registers_true.out
Normal file
2
compiler/tests/boolean/outputs_/registers_true.out
Normal file
@ -0,0 +1,2 @@
|
||||
[registers]
|
||||
r: bool = true;
|
@ -1,3 +0,0 @@
|
||||
function main() -> bool {
|
||||
return true
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
function main() -> bool {
|
||||
return true && false
|
||||
function main() {
|
||||
let a = true && false;
|
||||
|
||||
assert_eq!(a, false);
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
function main() -> bool {
|
||||
return true && true
|
||||
function main() {
|
||||
let a = true && true;
|
||||
|
||||
assert_eq!(a, true);
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return true && 1u32
|
||||
function main() {
|
||||
let a = true && 1u32;
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
function main() -> bool {
|
||||
return true || false
|
||||
function main() {
|
||||
let a = true || false;
|
||||
|
||||
assert_eq!(a, true);
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
function main() -> bool {
|
||||
return true || true
|
||||
function main() {
|
||||
let a = true || true;
|
||||
|
||||
assert_eq!(a, true);
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return true || 1u32
|
||||
function main() {
|
||||
let a = true || 1u32;
|
||||
}
|
@ -2,6 +2,6 @@ circuit Foo {
|
||||
x: u32
|
||||
}
|
||||
|
||||
function main() -> Foo {
|
||||
return Foo { x: 1u32 }
|
||||
function main() {
|
||||
let a = Foo { x: 1u32 };
|
||||
}
|
@ -3,5 +3,5 @@ circuit Foo {
|
||||
}
|
||||
|
||||
function main() {
|
||||
let c = Foo { y: 0u32 };
|
||||
let a = Foo { y: 0u32 };
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() {
|
||||
let c = Foo { };
|
||||
let a = Foo { };
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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 `::`
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ circuit Foo {
|
||||
}
|
||||
}
|
||||
|
||||
function main() -> u32 {
|
||||
return Foo::echo(1u32)
|
||||
function main() {
|
||||
let a = Foo::echo(1u32);
|
||||
|
||||
assert_eq!(a, 1u32);
|
||||
}
|
@ -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 `.`
|
||||
}
|
@ -4,6 +4,6 @@ circuit Foo {
|
||||
}
|
||||
}
|
||||
|
||||
function main() -> u32 {
|
||||
return Foo::echoed(1u32)
|
||||
function main() {
|
||||
let err = Foo::echoed(1u32);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -4,6 +4,6 @@ circuit Foo {
|
||||
}
|
||||
}
|
||||
|
||||
function main() -> Foo {
|
||||
return Foo::new()
|
||||
function main() {
|
||||
let a = Foo::new();
|
||||
}
|
@ -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);
|
||||
}
|
@ -8,5 +8,5 @@ circuit Foo {
|
||||
|
||||
function main() -> u32 {
|
||||
let foo = Foo { f: 1u32 };
|
||||
return foo.bar()
|
||||
let err = foo.bar();
|
||||
}
|
@ -4,7 +4,7 @@ circuit Foo {
|
||||
}
|
||||
}
|
||||
|
||||
function main() -> u32 {
|
||||
function main() {
|
||||
let foo = Foo { };
|
||||
return foo.bar()
|
||||
let err = foo.bar();
|
||||
}
|
1
compiler/tests/compiler_outputs/empty.out
Normal file
1
compiler/tests/compiler_outputs/empty.out
Normal file
@ -0,0 +1 @@
|
||||
[registers]
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
function main(f: field) -> field{
|
||||
return f
|
||||
}
|
2
compiler/tests/field/inputs/register_one.in
Normal file
2
compiler/tests/field/inputs/register_one.in
Normal file
@ -0,0 +1,2 @@
|
||||
[registers]
|
||||
r: field = 1;
|
2
compiler/tests/field/inputs/register_zero.in
Normal file
2
compiler/tests/field/inputs/register_zero.in
Normal file
@ -0,0 +1,2 @@
|
||||
[registers]
|
||||
r: field = 0;
|
@ -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, "ient);
|
||||
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);
|
||||
// }
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user