Merge pull request #53 from AleoHQ/feature/leo-inputs

Feature/leo inputs
This commit is contained in:
Collin Chin 2020-06-12 18:45:40 -07:00 committed by GitHub
commit 5661cbe927
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
88 changed files with 1606 additions and 196 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
/target
/tmp/
**.idea/
outputs/
*.DS_Store

19
Cargo.lock generated
View File

@ -515,6 +515,7 @@ dependencies = [
"env_logger",
"from-pest",
"leo-compiler",
"leo-inputs",
"log",
"rand",
"rand_core",
@ -550,6 +551,7 @@ version = "0.1.0"
dependencies = [
"hex",
"leo-ast",
"leo-inputs",
"leo-types",
"log",
"rand",
@ -562,11 +564,28 @@ dependencies = [
"thiserror",
]
[[package]]
name = "leo-inputs"
version = "0.1.0"
dependencies = [
"from-pest",
"pest",
"pest-ast",
"pest_derive",
"snarkos-algorithms",
"snarkos-curves",
"snarkos-errors",
"snarkos-gadgets",
"snarkos-models",
"thiserror",
]
[[package]]
name = "leo-types"
version = "0.1.0"
dependencies = [
"leo-ast",
"leo-inputs",
"snarkos-errors",
"snarkos-models",
"thiserror",

View File

@ -13,10 +13,11 @@ name = "leo"
path = "leo/main.rs"
[workspace]
members = [ "ast", "compiler", "types" ]
members = [ "ast", "compiler", "leo-inputs", "types" ]
[dependencies]
leo-compiler = { path = "compiler", version = "0.1.0" }
leo-inputs = { path = "leo-inputs", version = "0.1.0"}
snarkos-algorithms = { path = "../snarkOS/algorithms", version = "0.8.0" }
snarkos-curves = { path = "../snarkOS/curves", version = "0.8.0" }

View File

@ -381,6 +381,49 @@ test function expect_fail() {
}
```
# Leo Inputs
Public and private inputs for a Leo program are specified in the `inputs/` directory. The syntax for an input file is a limited subset of the Leo program syntax. The default inputs file is `inputs/inputs.leo`.
## Sections
A Leo input file is made up of sections. Sections are defined by a section header in brackets followed by one or more input definitions.
Section headers specify the target file which must have a main function with matching input names and types.
`inputs/inputs.leo`
```rust
[main] // <- section header
a: private u32 = 1; // <- private input
b: public u32 = 2; // <- public input
```
`src/main.leo`
```rust
function main(a: private u32, b: public u32) -> u32 {
let c: u32 = a + b;
return c
}
```
## Input Definitions
### Supported types
```rust
[main]
a: bool = true; // <- booleans
b: u8 = 2; // <- integers
c: field = 0; // <- fields
d: group = (0, 1)group // <- group tuples
```
### Arrays
```rust
[main]
a: private u8[4] = [0u8; 4]; // <- single
b: private u8[2][3] = [[0u8; 2]; 3]; // <- multi-dimensional
```
# Leo CLI
@ -395,6 +438,7 @@ leo new {$NAME}
This will create a new directory with a given package name. The new package will have a directory structure as follows:
```
- inputs # Your program inputs
- inputs.leo # Your program inputs for main.leo
- outputs # Your program outputs
- src
- lib.leo # Your program library
@ -455,6 +499,8 @@ leo prove
```
Leo starts by checking the `target` directory for an existing `.leo.pk` file. If it doesn't exist, it will proceed to run `leo setup` and then continue.
Next any input files in the `inputs` directory are parsed and all input values are passed to the program.
Once again, Leo uses cryptographic randomness from your machine to produce the proof. The proof is stored in the `target` directory as `.leo.proof`:
```

View File

@ -7,6 +7,7 @@ edition = "2018"
[dependencies]
leo-ast = { path = "../ast", version = "0.1.0" }
leo-types = { path = "../types", version = "0.1.0" }
leo-inputs = { path = "../leo-inputs", version = "0.1.0" }
snarkos-curves = { path = "../../snarkOS/curves", version = "0.8.0" }
snarkos-errors = { path = "../../snarkOS/errors", version = "0.8.0" }

View File

@ -6,7 +6,8 @@ use crate::{
GroupType,
};
use leo_ast::LeoParser;
use leo_types::{InputValue, Program};
use leo_inputs::LeoInputsParser;
use leo_types::{InputValue, Inputs, Program};
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
@ -15,6 +16,7 @@ use snarkos_models::{
};
use sha2::{Digest, Sha256};
use snarkos_models::curves::PairingEngine;
use std::{fs, marker::PhantomData, path::PathBuf};
#[derive(Clone)]
@ -22,7 +24,7 @@ pub struct Compiler<F: Field + PrimeField, G: GroupType<F>> {
package_name: String,
main_file_path: PathBuf,
program: Program,
program_inputs: Vec<Option<InputValue>>,
program_inputs: Inputs,
output: Option<ConstrainedValue<F, G>>,
_engine: PhantomData<F>,
}
@ -33,7 +35,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
package_name: "".to_string(),
main_file_path: PathBuf::new(),
program: Program::new(),
program_inputs: vec![],
program_inputs: Inputs::new(),
output: None,
_engine: PhantomData,
}
@ -44,7 +46,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
package_name,
main_file_path,
program: Program::new(),
program_inputs: vec![],
program_inputs: Inputs::new(),
output: None,
_engine: PhantomData,
};
@ -57,7 +59,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
}
pub fn set_inputs(&mut self, program_inputs: Vec<Option<InputValue>>) {
self.program_inputs = program_inputs;
self.program_inputs.set_inputs(program_inputs);
}
pub fn get_public_inputs<E: PairingEngine>(&self) -> Result<Vec<E::Fr>, CompilerError> {
Ok(self.program_inputs.get_public_inputs::<E>()?)
}
pub fn checksum(&self) -> Result<String, CompilerError> {
@ -77,7 +83,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
self,
cs: &mut CS,
) -> Result<ConstrainedValue<F, G>, CompilerError> {
generate_constraints(cs, self.program, self.program_inputs)
generate_constraints(cs, self.program, self.program_inputs.get_inputs())
}
pub fn compile_test_constraints(self, cs: &mut TestConstraintSystem<F>) -> Result<(), CompilerError> {
@ -86,8 +92,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
fn load_program(&mut self) -> Result<String, CompilerError> {
// Load the program syntax tree from the file path
let file_path = &self.main_file_path;
Ok(LeoParser::load_file(file_path)?)
Ok(LeoParser::load_file(&self.main_file_path)?)
}
pub fn parse_program(&mut self, program_string: &str) -> Result<(), CompilerError> {
@ -98,17 +103,26 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
let package_name = self.package_name.clone();
self.program = Program::from(syntax_tree, package_name);
self.program_inputs = vec![None; self.program.num_parameters];
self.program_inputs.set_inputs_size(self.program.expected_inputs.len());
log::debug!("Program parsing complete\n{:#?}", self.program);
Ok(())
}
pub fn parse_inputs(&mut self, input_file_path: &PathBuf, input_file_string: &str) -> Result<(), CompilerError> {
let syntax_tree = LeoInputsParser::parse_file(input_file_path, input_file_string)?;
// Check number/order of private parameters here
self.program_inputs = Inputs::from_inputs_file(syntax_tree, self.program.expected_inputs.clone())?;
Ok(())
}
}
impl<F: Field + PrimeField, G: GroupType<F>> ConstraintSynthesizer<F> for Compiler<F, G> {
fn generate_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
let _result = generate_constraints::<_, G, _>(cs, self.program, self.program_inputs).unwrap();
let _result = generate_constraints::<_, G, _>(cs, self.program, self.program_inputs.get_inputs()).unwrap();
// Write results to file or something

View File

@ -1,5 +1,6 @@
use crate::errors::{FunctionError, ImportError};
use leo_ast::{ParserError, SyntaxError};
use leo_inputs::InputParserError;
use leo_types::IntegerError;
use std::{io, path::PathBuf};
@ -15,6 +16,9 @@ pub enum CompilerError {
#[error("{}", _0)]
ImportError(#[from] ImportError),
#[error("{}", _0)]
InputParserError(#[from] InputParserError),
#[error("{}", _0)]
IntegerError(#[from] IntegerError),

View File

@ -1,72 +0,0 @@
/// Visibility
visibility_public = { "public" }
visibility_private = { "private" }
visibility = { visibility_public | visibility_private }
/// Types
ty_u32 = {"u32"}
ty_field = {"fe"}
ty_bool = {"bool"}
ty_basic = { ty_u32 | ty_field | ty_bool }
ty_struct = { variable }
ty_array = {ty_basic ~ ("[" ~ value ~ "]")+ }
ty = { ty_array | ty_basic | ty_struct }
/// Values
value_number = @{ "0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* }
value_u32 = { value_number ~ ty_u32? }
value_field = { value_number ~ ty_field }
value_boolean = { "true" | "false" }
value = { value_field | value_boolean | value_u32 }
/// Variables
protected_name = { visibility | "return" }
variable = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
/// Arrays
inline_array_inner = _{(expression_term ~ ("," ~ NEWLINE* ~ expression_term)*)?}
expression_array_inline = { "[" ~ NEWLINE* ~ inline_array_inner ~ NEWLINE* ~ "]"}
expression_array_initializer = { "[" ~ expression_term ~ ";" ~ value ~ "]" }
/// Structs
inline_struct_member = { variable ~ ":" ~ expression_term }
inline_struct_member_list = _{(inline_struct_member ~ ("," ~ NEWLINE* ~ inline_struct_member)*)? ~ ","? }
expression_inline_struct = { variable ~ "{" ~ NEWLINE* ~ inline_struct_member_list ~ NEWLINE* ~ "}" }
/// Expressions
expression_primitive = { value | variable }
expression_term = {
expression_inline_struct
| expression_primitive
| expression_array_inline
| expression_array_initializer
}
/// Functions
parameter = { variable ~ ":" ~ visibility? ~ ty }
function_name = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
/// Section
header = { "[" ~ function_name ~ "]" }
assignment = { parameter ~ "=" ~ expression_term }
section = { header ~ NEWLINE+ ~ assignment* ~ NEWLINE* }
/// Utilities
COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }
WHITESPACE = _{ " " | "\t" ~ (NEWLINE)* }
/// Program File
file = { SOI ~ NEWLINE* ~ section* ~ NEWLINE* ~ EOI }

View File

@ -5,6 +5,7 @@ use leo_compiler::{
};
use leo_types::{InputValue, Integer, IntegerError};
use leo_inputs::types::{IntegerType, U32Type};
use snarkos_models::gadgets::utilities::uint::UInt32;
// [1, 1, 1]
@ -52,6 +53,10 @@ fn fail_synthesis(program: EdwardsTestCompiler) {
}
}
pub(crate) fn input_value_u32_one() -> InputValue {
InputValue::Integer(IntegerType::U32Type(U32Type {}), 1)
}
// Expressions
#[test]
@ -101,7 +106,7 @@ 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![InputValue::Integer(1u128); 3]))]);
program.set_inputs(vec![Some(InputValue::Array(vec![input_value_u32_one(); 3]))]);
output_ones(program)
}
@ -111,7 +116,7 @@ fn test_input_array_fail() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Integer(1u128))]);
program.set_inputs(vec![Some(input_value_u32_one())]);
fail_array(program);
}

View File

@ -3,8 +3,8 @@ use leo_compiler::{
errors::{BooleanError, CompilerError, ExpressionError, FunctionError, StatementError},
ConstrainedValue,
};
use leo_types::InputValue;
use crate::array::input_value_u32_one;
use snarkos_models::gadgets::utilities::boolean::Boolean;
pub fn output_expected_boolean(program: EdwardsTestCompiler, boolean: bool) {
@ -76,7 +76,7 @@ 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::Integer(1u128))]);
program.set_inputs(vec![Some(input_value_u32_one())]);
fail_boolean(program);
}

View File

@ -0,0 +1,2 @@
[main]
b: private bool = true;

View File

@ -0,0 +1,2 @@
[main]
bad_name: private bool = true;

View File

@ -0,0 +1,2 @@
[main]
b: private u8 = 1;

View File

@ -0,0 +1,2 @@
[main]
b: public bool = true;

View File

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

View File

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

View File

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

View File

@ -0,0 +1,72 @@
use crate::{boolean::output_true, parse_program};
use leo_compiler::errors::CompilerError;
use leo_inputs::InputParserError;
use std::path::PathBuf;
fn fail_input_parser(error: CompilerError) {
match error {
CompilerError::InputParserError(InputParserError::InputNotFound(_)) => {}
err => panic!("expected input parser error, got {}", err),
}
}
#[test]
fn test_inputs_pass() {
let program_bytes = include_bytes!("main.leo");
let input_bytes = include_bytes!("inputs.leo");
let input_string = String::from_utf8_lossy(input_bytes);
let mut program = parse_program(program_bytes).unwrap();
program.parse_inputs(&PathBuf::new(), &input_string).unwrap();
output_true(program);
}
#[test]
fn test_inputs_fail_name() {
let program_bytes = include_bytes!("main.leo");
let input_bytes = include_bytes!("inputs_fail_name.leo");
let input_string = String::from_utf8_lossy(input_bytes);
let mut program = parse_program(program_bytes).unwrap();
let error = program.parse_inputs(&PathBuf::new(), &input_string).unwrap_err();
fail_input_parser(error);
}
#[test]
fn test_inputs_fail_type() {
let program_bytes = include_bytes!("main.leo");
let input_bytes = include_bytes!("inputs_fail_type.leo");
let input_string = String::from_utf8_lossy(input_bytes);
let mut program = parse_program(program_bytes).unwrap();
let error = program.parse_inputs(&PathBuf::new(), &input_string).unwrap_err();
fail_input_parser(error);
}
#[test]
fn test_inputs_fail_visibility() {
let program_bytes = include_bytes!("main.leo");
let input_bytes = include_bytes!("inputs_fail_visibility.leo");
let input_string = String::from_utf8_lossy(input_bytes);
let mut program = parse_program(program_bytes).unwrap();
let error = program.parse_inputs(&PathBuf::new(), &input_string).unwrap_err();
fail_input_parser(error);
}
#[test]
fn test_inputs_multiple() {
let program_bytes = include_bytes!("main_multiple.leo");
let input_bytes = include_bytes!("inputs_multiple.leo");
let input_string = String::from_utf8_lossy(input_bytes);
let mut program = parse_program(program_bytes).unwrap();
program.parse_inputs(&PathBuf::new(), &input_string).unwrap();
output_true(program);
}

View File

@ -1,5 +1,5 @@
macro_rules! test_uint {
($name: ident, $_type: ty, $gadget: ty) => {
($name: ident, $_type: ty, $integer_type: expr, $gadget: ty) => {
pub struct $name {}
impl $name {
@ -31,7 +31,7 @@ macro_rules! test_uint {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Integer(num as u128))]);
program.set_inputs(vec![Some(InputValue::Integer($integer_type, num as u128))]);
output_expected_allocated(program, expected);
@ -61,8 +61,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r2 as u128)),
]);
output_expected_allocated(program, sum_allocated);
@ -83,8 +83,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r2 as u128)),
]);
output_expected_allocated(program, difference_allocated);
@ -105,8 +105,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r2 as u128)),
]);
output_expected_allocated(program, product_allocated);
@ -127,8 +127,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r2 as u128)),
]);
output_expected_allocated(program, quotient_allocated);
@ -150,8 +150,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r2 as u128)),
]);
output_expected_allocated(program, result_allocated);
@ -167,8 +167,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
]);
output_true(program);
@ -181,8 +181,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r2 as u128)),
]);
output_expected_boolean(program, result);
@ -198,8 +198,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
]);
output_true(program);
@ -212,8 +212,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r2 as u128)),
]);
output_expected_boolean(program, result);
@ -229,8 +229,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
]);
output_false(program);
@ -243,8 +243,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r2 as u128)),
]);
output_expected_boolean(program, result);
@ -260,8 +260,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
]);
output_true(program);
@ -274,8 +274,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r2 as u128)),
]);
output_expected_boolean(program, result);
@ -291,8 +291,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
]);
output_false(program);
@ -305,8 +305,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r2 as u128)),
]);
output_expected_boolean(program, result);
@ -322,8 +322,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
]);
let _ = get_output(program);
@ -338,8 +338,8 @@ macro_rules! test_uint {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r2 as u128)),
]);
let mut cs = TestConstraintSystem::<Fq>::new();
@ -363,8 +363,8 @@ macro_rules! test_uint {
// true -> field 1
program_1.set_inputs(vec![
Some(InputValue::Boolean(true)),
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r2 as u128)),
]);
output_expected_allocated(program_1, g1);
@ -372,8 +372,8 @@ macro_rules! test_uint {
// false -> field 2
program_2.set_inputs(vec![
Some(InputValue::Boolean(false)),
Some(InputValue::Integer(r1 as u128)),
Some(InputValue::Integer(r2 as u128)),
Some(InputValue::Integer($integer_type, r1 as u128)),
Some(InputValue::Integer($integer_type, r2 as u128)),
]);
output_expected_allocated(program_2, g2);

View File

@ -7,6 +7,7 @@ use crate::{
EdwardsTestCompiler,
};
use leo_compiler::ConstrainedValue;
use leo_inputs::types::{IntegerType, U128Type};
use leo_types::{InputValue, Integer};
use snarkos_curves::edwards_bls12::Fq;
@ -30,7 +31,7 @@ fn output_expected_allocated(program: EdwardsTestCompiler, expected: UInt128) {
#[test]
#[ignore] // temporarily ignore memory expensive tests for travis
fn test_u128() {
test_uint!(TestU128, u128, UInt128);
test_uint!(TestU128, u128, IntegerType::U128Type(U128Type {}), UInt128);
TestU128::test_min(std::u128::MIN);
TestU128::test_max(std::u128::MAX);

View File

@ -7,6 +7,7 @@ use crate::{
EdwardsTestCompiler,
};
use leo_compiler::ConstrainedValue;
use leo_inputs::types::{IntegerType, U16Type};
use leo_types::{InputValue, Integer};
use snarkos_curves::edwards_bls12::Fq;
@ -29,7 +30,7 @@ fn output_expected_allocated(program: EdwardsTestCompiler, expected: UInt16) {
#[test]
fn test_u16() {
test_uint!(Testu16, u16, UInt16);
test_uint!(Testu16, u16, IntegerType::U16Type(U16Type {}), UInt16);
Testu16::test_min(std::u16::MIN);
Testu16::test_max(std::u16::MAX);

View File

@ -7,6 +7,7 @@ use crate::{
EdwardsTestCompiler,
};
use leo_compiler::ConstrainedValue;
use leo_inputs::types::{IntegerType, U32Type};
use leo_types::{InputValue, Integer};
use snarkos_curves::edwards_bls12::Fq;
@ -47,7 +48,7 @@ pub(crate) fn output_one(program: EdwardsTestCompiler) {
#[test]
fn test_u32() {
test_uint!(TestU32, u32, UInt32);
test_uint!(TestU32, u32, IntegerType::U32Type(U32Type {}), UInt32);
TestU32::test_min(std::u32::MIN);
TestU32::test_max(std::u32::MAX);

View File

@ -7,6 +7,7 @@ use crate::{
EdwardsTestCompiler,
};
use leo_compiler::ConstrainedValue;
use leo_inputs::types::{IntegerType, U64Type};
use leo_types::{InputValue, Integer};
use snarkos_curves::edwards_bls12::Fq;
@ -30,7 +31,7 @@ fn output_expected_allocated(program: EdwardsTestCompiler, expected: UInt64) {
#[test]
#[ignore] //temporarily ignore memory expensive tests for travis
fn test_u64() {
test_uint!(Testu64, u64, UInt64);
test_uint!(Testu64, u64, IntegerType::U64Type(U64Type {}), UInt64);
Testu64::test_min(std::u64::MIN);
Testu64::test_max(std::u64::MAX);

View File

@ -7,6 +7,7 @@ use crate::{
EdwardsTestCompiler,
};
use leo_compiler::ConstrainedValue;
use leo_inputs::types::{IntegerType, U8Type};
use leo_types::{InputValue, Integer};
use snarkos_curves::edwards_bls12::Fq;
@ -29,7 +30,7 @@ fn output_expected_allocated(program: EdwardsTestCompiler, expected: UInt8) {
#[test]
fn test_u8() {
test_uint!(Testu8, u8, UInt8);
test_uint!(Testu8, u8, IntegerType::U8Type(U8Type {}), UInt8);
Testu8::test_min(std::u8::MIN);
Testu8::test_max(std::u8::MAX);

View File

@ -5,6 +5,7 @@ pub mod field;
pub mod function;
pub mod group;
pub mod import;
pub mod inputs;
pub mod integers;
pub mod mutability;
pub mod statements;
@ -19,6 +20,7 @@ use leo_compiler::{
use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::r1cs::TestConstraintSystem;
use std::path::PathBuf;
pub type EdwardsTestCompiler = Compiler<Fq, EdwardsGroupType>;
pub type EdwardsConstrainedValue = ConstrainedValue<Fq, EdwardsGroupType>;
@ -51,3 +53,13 @@ pub(crate) fn parse_program(bytes: &[u8]) -> Result<EdwardsTestCompiler, Compile
Ok(compiler)
}
pub(crate) fn parse_inputs(bytes: &[u8]) -> Result<EdwardsTestCompiler, CompilerError> {
let inputs_string = String::from_utf8_lossy(bytes);
let mut compiler = EdwardsTestCompiler::new();
compiler.parse_inputs(&PathBuf::new(), &inputs_string)?;
Ok(compiler)
}

View File

@ -3,8 +3,9 @@ use leo_compiler::{
errors::{CompilerError, FunctionError, StatementError},
ConstrainedValue,
};
use leo_types::{InputValue, Integer};
use leo_types::Integer;
use crate::array::input_value_u32_one;
use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::{r1cs::TestConstraintSystem, utilities::uint::UInt32};
@ -84,7 +85,7 @@ fn test_function_input() {
let bytes = include_bytes!("function_input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Integer(1))]);
program.set_inputs(vec![Some(input_value_u32_one())]);
mut_fail(program);
}
@ -93,6 +94,6 @@ fn test_function_input_mut() {
let bytes = include_bytes!("function_input_mut.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Integer(1))]);
program.set_inputs(vec![Some(input_value_u32_one())]);
mut_success(program);
}

View File

@ -0,0 +1,2 @@
[main]
a: private u32 = 5

View File

@ -1,6 +1,7 @@
use crate::parse_program;
use crate::{parse_inputs, parse_program};
use leo_ast::ParserError;
use leo_compiler::errors::CompilerError;
use leo_inputs::InputParserError;
#[test]
fn test_semicolon() {
@ -12,3 +13,14 @@ fn test_semicolon() {
_ => panic!("test_semicolon failed the wrong expected error, should be a ParserError"),
}
}
#[test]
fn inputs_syntax_error() {
let bytes = include_bytes!("inputs_semicolon.leo");
let error = parse_inputs(bytes).err().unwrap();
match error {
CompilerError::InputParserError(InputParserError::SyntaxError(_)) => {}
_ => panic!("inputs syntax error should be a ParserError"),
}
}

18
leo-inputs/Cargo.toml Normal file
View File

@ -0,0 +1,18 @@
[package]
name = "leo-inputs"
version = "0.1.0"
authors = ["The Aleo Team <hello@aleo.org>"]
edition = "2018"
[dependencies]
snarkos-algorithms = { path = "../../snarkOS/algorithms", version = "0.8.0" }
snarkos-curves = { path = "../../snarkOS/curves", version = "0.8.0" }
snarkos-errors = { path = "../../snarkOS/errors", version = "0.8.0" }
snarkos-gadgets = { path = "../../snarkOS/gadgets", version = "0.8.0" }
snarkos-models = { path = "../../snarkOS/models", version = "0.8.0" }
from-pest = { version = "0.3.1" }
pest = { version = "2.0" }
pest-ast = { version = "0.3.3" }
pest_derive = { version = "2.0" }
thiserror = { version = "1.0" }

4
leo-inputs/input.leo Normal file
View File

@ -0,0 +1,4 @@
[main]
a: private u32 = 5;
b: public field = 1field;
c: private bool = true;

View File

@ -0,0 +1,14 @@
use crate::{ast::Rule, common::LineEnd, expressions::Expression, parameters::Parameter};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::assignment))]
pub struct Assignment<'ast> {
pub parameter: Parameter<'ast>,
pub expression: Expression<'ast>,
pub line_end: LineEnd,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,2 @@
pub mod assignment;
pub use assignment::*;

14
leo-inputs/src/ast.rs Normal file
View File

@ -0,0 +1,14 @@
//! Abstract syntax tree (ast) representation from leo-inputs.pest.
use pest::{error::Error, iterators::Pairs, Parser, Span};
#[derive(Parser)]
#[grammar = "leo-inputs.pest"]
pub struct LanguageParser;
pub fn parse(input: &str) -> Result<Pairs<Rule>, Error<Rule>> {
LanguageParser::parse(Rule::file, input)
}
pub fn span_into_string(span: Span) -> String {
span.as_str().to_string()
}

View File

@ -0,0 +1,7 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::EOI))]
pub struct EOI;

View File

@ -0,0 +1,20 @@
use crate::ast::{span_into_string, Rule};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::identifier))]
pub struct Identifier<'ast> {
#[pest_ast(outer(with(span_into_string)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Identifier<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}

View File

@ -0,0 +1,7 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::LINE_END))]
pub struct LineEnd;

View File

@ -0,0 +1,11 @@
pub mod eoi;
pub use eoi::*;
pub mod identifier;
pub use identifier::*;
pub mod line_end;
pub use line_end::*;
pub mod visibility;
pub use visibility::*;

View File

@ -0,0 +1,18 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::visibility))]
pub enum Visibility {
Public(Public),
Private(Private),
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::visibility_public))]
pub struct Public {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::visibility_private))]
pub struct Private {}

View File

@ -0,0 +1,5 @@
pub mod parser;
pub use parser::*;
pub mod syntax;
pub use syntax::*;

View File

@ -0,0 +1,43 @@
use crate::{ast::Rule, errors::SyntaxError};
use pest::error::Error;
use std::{num::ParseIntError, path::PathBuf, str::ParseBoolError};
#[derive(Debug, Error)]
pub enum InputParserError {
#[error("expected array length {}, got {}", _0, _1)]
InvalidArrayLength(usize, usize),
#[error("expected type {}, got {}", _0, _1)]
IncompatibleTypes(String, String),
#[error("Program input value {} not found", _0)]
InputNotFound(String),
#[error("Cannot read from the provided file path - {:?}", _0)]
FileReadError(PathBuf),
#[error("{}", _0)]
ParseBoolError(#[from] ParseBoolError),
#[error("{}", _0)]
ParseIntError(#[from] ParseIntError),
#[error("cannot parse {} as field", _0)]
ParseFieldError(String),
#[error("{}", _0)]
SyntaxError(#[from] SyntaxError),
#[error("Unable to construct abstract syntax tree")]
SyntaxTreeError,
#[error("found an empty array dimension in type")]
UndefinedArrayDimension,
}
impl From<Error<Rule>> for InputParserError {
fn from(error: Error<Rule>) -> Self {
InputParserError::SyntaxError(SyntaxError::from(error))
}
}

View File

@ -0,0 +1,29 @@
use crate::ast::Rule;
use pest::error::Error;
#[derive(Debug, Error)]
pub enum SyntaxError {
#[error("aborting due to syntax error")]
Error,
}
impl From<Error<Rule>> for SyntaxError {
fn from(mut error: Error<Rule>) -> Self {
error = error.renamed_rules(|rule| match *rule {
Rule::LINE_END => "`;`".to_owned(),
Rule::type_integer => "`u32`".to_owned(),
Rule::type_field => "`field`".to_owned(),
Rule::type_group => "`group`".to_owned(),
Rule::file => "an import, circuit, or function".to_owned(),
Rule::identifier => "a variable name".to_owned(),
Rule::type_ => "a type".to_owned(),
rule => format!("{:?}", rule),
});
println!("{}\n", error);
SyntaxError::Error
}
}

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, expressions::Expression, values::NumberValue};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::expression_array_initializer))]
pub struct ArrayInitializerExpression<'ast> {
pub expression: Box<Expression<'ast>>,
pub count: NumberValue<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,12 @@
use crate::{ast::Rule, expressions::Expression};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::expression_array_inline))]
pub struct ArrayInlineExpression<'ast> {
pub expressions: Vec<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,32 @@
use crate::{ast::Rule, expressions::*, values::Value};
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::expression))]
pub enum Expression<'ast> {
ArrayInline(ArrayInlineExpression<'ast>),
ArrayInitializer(ArrayInitializerExpression<'ast>),
Value(Value<'ast>),
}
impl<'ast> fmt::Display for Expression<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Expression::Value(ref expression) => write!(f, "{}", expression),
Expression::ArrayInline(ref expression) => {
for (i, spread_or_expression) in expression.expressions.iter().enumerate() {
write!(f, "{}", spread_or_expression)?;
if i < expression.expressions.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "")
}
Expression::ArrayInitializer(ref expression) => {
write!(f, "[{} ; {}]", expression.expression, expression.count)
}
}
}
}

View File

@ -0,0 +1,8 @@
pub mod array_initializer_expression;
pub use array_initializer_expression::*;
pub mod array_inline_expression;
pub use array_inline_expression::*;
pub mod expression;
pub use expression::*;

View File

@ -0,0 +1,13 @@
use crate::{ast::Rule, common::EOI, sections::Section};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::file))]
pub struct File<'ast> {
pub sections: Vec<Section<'ast>>,
pub eoi: EOI,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,2 @@
pub mod file;
pub use file::*;

View File

@ -0,0 +1,115 @@
/// Common
// Declared in common/identifier.rs
identifier = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
protected_name = { visibility | "let" | "for"| "if" | "else" | "as" | "return" }
// Declared in common/line_end.rs
LINE_END = { ";" ~ NEWLINE* }
// Declared in common/visibility.rs
visibility = { visibility_public | visibility_private }
visibility_public = { "public" }
visibility_private = { "private" }
/// Types
// Declared in types/type_.rs
type_ = { type_array | type_data }
// Declared in types/integer_type.rs
type_integer = {
type_u8
| type_u16
| type_u32
| type_u64
| type_u128
}
type_u8 = { "u8" }
type_u16 = { "u16" }
type_u32 = { "u32" }
type_u64 = { "u64" }
type_u128 = { "u128" }
// Declared in types/field_type.rs
type_field = { "field" }
// Declared in types/group_type.rs
type_group = { "group" }
// Declared in types/boolean_type.rs
type_boolean = { "bool" }
// Declared in types/data_type.rs
type_data = { type_field | type_group | type_boolean | type_integer }
// Declared in types/array_type.rs
type_array = { type_data ~ ("[" ~ value_number ~ "]")+ }
/// Values
// Declared in values/value.rs
value = { value_field | value_group | value_boolean | value_integer | value_implicit }
// Declared in values/number_value.rs
value_number = @{ "0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* }
// Declared in values/number_implicit_value.rs
value_implicit = { value_number }
// Declared in values/integer_value.rs
value_integer = { value_number ~ type_integer }
// Declared in values/boolean_value.rs
value_boolean = { "true" | "false" }
// Declared in values/field_value.rs
value_field = { value_number ~ type_field }
// Declared in values/group_value.rs
value_group = { group_tuple ~ type_group }
group_tuple = { "(" ~ NEWLINE* ~ value_number ~ "," ~ NEWLINE* ~ value_number ~ NEWLINE* ~")" }
/// Expressions
// Declared in expressions/array_initializer_expression.rs
expression_array_initializer = { "[" ~ expression ~ ";" ~ value_number ~ "]" }
// Declared in expressions/array_inline_expression.rs
expression_array_inline = { "[" ~ NEWLINE* ~ inline_array_inner ~ NEWLINE* ~ "]"}
inline_array_inner = _{ (expression ~ ("," ~ NEWLINE* ~ expression)*)? }
// Declared in expressions/expression.rs
expression = {
expression_array_inline
| expression_array_initializer
| value
}
/// Parameters
// Declared in parameters/parameters.rs
parameter = { identifier ~ ":" ~ visibility? ~ type_ }
/// Section
// Declared in sections/section.rs
section = { header ~ NEWLINE+ ~ (assignment ~ NEWLINE*)* }
// Declared in sections/header.rs
header = { "[" ~ identifier ~ "]" }
/// Assignments
// Declared in assignment/assignment.rs
assignment = { parameter ~ "=" ~ NEWLINE* ~ expression ~ LINE_END }
/// Utilities
COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }
WHITESPACE = _{ " " | "\t" ~ (NEWLINE)* }
/// Files
// Declared in files/file.rs
file = { SOI ~ NEWLINE* ~ section* ~ NEWLINE* ~ EOI }

43
leo-inputs/src/lib.rs Normal file
View File

@ -0,0 +1,43 @@
#[macro_use]
extern crate pest_derive;
#[macro_use]
extern crate thiserror;
pub mod errors;
pub use errors::*;
//extern crate from_pest;
pub mod assignments;
mod ast;
pub mod common;
pub mod expressions;
pub mod files;
pub mod parameters;
pub mod sections;
pub mod types;
pub mod values;
use from_pest::FromPest;
use std::{fs, path::PathBuf};
pub struct LeoInputsParser;
impl LeoInputsParser {
/// Reads in the given file path into a string.
pub fn load_file(file_path: &PathBuf) -> Result<String, InputParserError> {
Ok(fs::read_to_string(file_path).map_err(|_| InputParserError::FileReadError(file_path.clone()))?)
}
/// Parses the input file and constructs a syntax tree.
pub fn parse_file<'a>(file_path: &'a PathBuf, input_file: &'a str) -> Result<files::File<'a>, InputParserError> {
// Parse the file using leo.pest
let mut file = ast::parse(input_file)
.map_err(|error| InputParserError::from(error.with_path(file_path.to_str().unwrap())))?;
// Build the abstract syntax tree
let syntax_tree = files::File::from_pest(&mut file).map_err(|_| InputParserError::SyntaxTreeError)?;
// println!("{:?}", syntax_tree);
Ok(syntax_tree)
}
}

13
leo-inputs/src/main.rs Normal file
View File

@ -0,0 +1,13 @@
use leo_inputs::{self, LeoInputsParser};
use std::env::current_dir;
fn main() {
let mut path = current_dir().unwrap();
path.push("input.leo");
let input_file = &LeoInputsParser::load_file(&path).expect("cannot read file");
let syntax_tree = LeoInputsParser::parse_file(&path, input_file).unwrap();
println!("tree: {:#?}", syntax_tree);
}

View File

@ -0,0 +1,2 @@
pub mod parameter;
pub use parameter::*;

View File

@ -0,0 +1,18 @@
use crate::{
ast::Rule,
common::{Identifier, Visibility},
types::Type,
};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::parameter))]
pub struct Parameter<'ast> {
pub variable: Identifier<'ast>,
pub visibility: Option<Visibility>,
pub type_: Type<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,12 @@
use crate::{ast::Rule, common::Identifier};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::header))]
pub struct Header<'ast> {
pub name: Identifier<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,5 @@
pub mod header;
pub use header::*;
pub mod section;
pub use section::*;

View File

@ -0,0 +1,13 @@
use crate::{assignments::Assignment, ast::Rule, sections::Header};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::section))]
pub struct Section<'ast> {
pub header: Header<'ast>,
pub assignments: Vec<Assignment<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -0,0 +1,29 @@
use crate::{ast::Rule, types::DataType, values::NumberValue};
use pest::Span;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_array))]
pub struct ArrayType<'ast> {
pub _type: DataType,
pub dimensions: Vec<NumberValue<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> ArrayType<'ast> {
pub fn next_dimension(&mut self) -> Option<NumberValue<'ast>> {
self.dimensions.pop()
}
}
impl<'ast> std::fmt::Display for ArrayType<'ast> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self._type)?;
for row in &self.dimensions {
write!(f, "[{}]", row)?;
}
write!(f, "")
}
}

View File

@ -0,0 +1,7 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_boolean))]
pub struct BooleanType {}

View File

@ -0,0 +1,26 @@
use crate::{
ast::Rule,
types::{BooleanType, FieldType, GroupType, IntegerType},
};
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_data))]
pub enum DataType {
Integer(IntegerType),
Field(FieldType),
Group(GroupType),
Boolean(BooleanType),
}
impl std::fmt::Display for DataType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
DataType::Integer(ref integer) => write!(f, "{}", integer),
DataType::Field(_) => write!(f, "field"),
DataType::Group(_) => write!(f, "group"),
DataType::Boolean(_) => write!(f, "bool"),
}
}
}

View File

@ -0,0 +1,7 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_field))]
pub struct FieldType {}

View File

@ -0,0 +1,7 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_group))]
pub struct GroupType {}

View File

@ -0,0 +1,45 @@
use crate::ast::Rule;
use pest_ast::FromPest;
#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
#[pest_ast(rule(Rule::type_integer))]
pub enum IntegerType {
U8Type(U8Type),
U16Type(U16Type),
U32Type(U32Type),
U64Type(U64Type),
U128Type(U128Type),
}
#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
#[pest_ast(rule(Rule::type_u8))]
pub struct U8Type {}
#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
#[pest_ast(rule(Rule::type_u16))]
pub struct U16Type {}
#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
#[pest_ast(rule(Rule::type_u32))]
pub struct U32Type {}
#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
#[pest_ast(rule(Rule::type_u64))]
pub struct U64Type {}
#[derive(Clone, Debug, FromPest, PartialEq, Eq)]
#[pest_ast(rule(Rule::type_u128))]
pub struct U128Type {}
impl std::fmt::Display for IntegerType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
IntegerType::U8Type(_) => write!(f, "u8"),
IntegerType::U16Type(_) => write!(f, "u16"),
IntegerType::U32Type(_) => write!(f, "u32"),
IntegerType::U64Type(_) => write!(f, "u64"),
IntegerType::U128Type(_) => write!(f, "u128"),
}
}
}

View File

@ -0,0 +1,20 @@
pub mod array_type;
pub use array_type::*;
pub mod boolean_type;
pub use boolean_type::*;
pub mod data_type;
pub use data_type::*;
pub mod field_type;
pub use field_type::*;
pub mod group_type;
pub use group_type::*;
pub mod integer_type;
pub use integer_type::*;
pub mod type_;
pub use type_::*;

View File

@ -0,0 +1,20 @@
use crate::{ast::Rule, types::*};
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_))]
pub enum Type<'ast> {
Basic(DataType),
Array(ArrayType<'ast>),
}
impl<'ast> fmt::Display for Type<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Type::Basic(ref basic) => write!(f, "{}", basic),
Type::Array(ref array) => write!(f, "{}", array),
}
}
}

View File

@ -0,0 +1,20 @@
use crate::ast::{span_into_string, Rule};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_boolean))]
pub struct BooleanValue<'ast> {
#[pest_ast(outer(with(span_into_string)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for BooleanValue<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}

View File

@ -0,0 +1,20 @@
use crate::{ast::Rule, types::FieldType, values::NumberValue};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_field))]
pub struct FieldValue<'ast> {
pub number: NumberValue<'ast>,
pub _type: FieldType,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for FieldValue<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.number)
}
}

View File

@ -0,0 +1,35 @@
use crate::{ast::Rule, types::GroupType, values::NumberValue};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_group))]
pub struct GroupValue<'ast> {
pub value: GroupTuple<'ast>,
pub _type: GroupType,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for GroupValue<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::group_tuple))]
pub struct GroupTuple<'ast> {
pub x: NumberValue<'ast>,
pub y: NumberValue<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for GroupTuple<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}

View File

@ -0,0 +1,20 @@
use crate::{ast::Rule, types::IntegerType, values::NumberValue};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_integer))]
pub struct IntegerValue<'ast> {
pub number: NumberValue<'ast>,
pub _type: IntegerType,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for IntegerValue<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.number)
}
}

View File

@ -0,0 +1,20 @@
pub mod boolean_value;
pub use boolean_value::*;
pub mod field_value;
pub use field_value::*;
pub mod group_value;
pub use group_value::*;
pub mod integer_value;
pub use integer_value::*;
pub mod number_implicit_value;
pub use number_implicit_value::*;
pub mod number_value;
pub use number_value::*;
pub mod value;
pub use value::*;

View File

@ -0,0 +1,19 @@
use crate::{ast::Rule, values::NumberValue};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_implicit))]
pub struct NumberImplicitValue<'ast> {
pub number: NumberValue<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for NumberImplicitValue<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.number)
}
}

View File

@ -0,0 +1,20 @@
use crate::ast::{span_into_string, Rule};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value_number))]
pub struct NumberValue<'ast> {
#[pest_ast(outer(with(span_into_string)))]
pub value: String,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for NumberValue<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}

View File

@ -0,0 +1,42 @@
use crate::{
ast::Rule,
values::{BooleanValue, FieldValue, GroupValue, IntegerValue, NumberImplicitValue},
};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::value))]
pub enum Value<'ast> {
Integer(IntegerValue<'ast>),
Field(FieldValue<'ast>),
Group(GroupValue<'ast>),
Boolean(BooleanValue<'ast>),
Implicit(NumberImplicitValue<'ast>),
}
impl<'ast> Value<'ast> {
pub fn span(&self) -> &Span<'ast> {
match self {
Value::Integer(value) => &value.span,
Value::Field(value) => &value.span,
Value::Group(value) => &value.span,
Value::Boolean(value) => &value.span,
Value::Implicit(value) => &value.span,
}
}
}
impl<'ast> fmt::Display for Value<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Value::Integer(ref value) => write!(f, "{}", value),
Value::Field(ref value) => write!(f, "{}", value),
Value::Group(ref value) => write!(f, "{}", value),
Value::Boolean(ref value) => write!(f, "{}", value),
Value::Implicit(ref value) => write!(f, "{}", value),
}
}
}

View File

@ -6,6 +6,7 @@ use crate::{
files::{Gitignore, MainFile, Manifest},
};
use crate::files::InputsFile;
use clap::ArgMatches;
use std::env::current_dir;
@ -65,6 +66,12 @@ impl CLI for InitCommand {
// Create the inputs directory
InputsDirectory::create(&path)?;
// Verify the inputs file does not exist
if !InputsFile::exists_at(&path) {
// Create the main file in the source directory
InputsFile::new(&package_name).write_to(&path)?;
}
// Verify the main file does not exist
if !MainFile::exists_at(&path) {
// Create the main file in the source directory

View File

@ -6,11 +6,15 @@ use crate::{
files::{Manifest, ProofFile},
};
use snarkos_algorithms::snark::{create_random_proof, Proof};
use snarkos_algorithms::snark::{create_random_proof, PreparedVerifyingKey, Proof};
use snarkos_curves::bls12_377::Bls12_377;
use crate::{directories::INPUTS_DIRECTORY_NAME, files::INPUTS_FILE_NAME};
use clap::ArgMatches;
use leo_compiler::{compiler::Compiler, edwards_bls12::EdwardsGroupType};
use leo_inputs::LeoInputsParser;
use rand::thread_rng;
use snarkos_curves::edwards_bls12::Fq;
use std::{convert::TryFrom, env::current_dir, time::Instant};
#[derive(Debug)]
@ -18,7 +22,11 @@ pub struct ProveCommand;
impl CLI for ProveCommand {
type Options = ();
type Output = Proof<Bls12_377>;
type Output = (
Compiler<Fq, EdwardsGroupType>,
Proof<Bls12_377>,
PreparedVerifyingKey<Bls12_377>,
);
const ABOUT: AboutType = "Run the program and produce a proof";
const ARGUMENTS: &'static [ArgumentType] = &[];
@ -34,17 +42,26 @@ impl CLI for ProveCommand {
#[cfg_attr(tarpaulin, skip)]
fn output(options: Self::Options) -> Result<Self::Output, CLIError> {
let (program, parameters, _) = SetupCommand::output(options)?;
let (mut program, parameters, prepared_verifying_key) = SetupCommand::output(options)?;
// Get the package name
let path = current_dir()?;
let package_name = Manifest::try_from(&path)?.get_package_name();
// Construct the path to the inputs file in the inputs directory
let mut inputs_file_path = path.clone();
inputs_file_path.push(INPUTS_DIRECTORY_NAME);
inputs_file_path.push(INPUTS_FILE_NAME);
// Fetch program inputs here
let inputs_file_string = LeoInputsParser::load_file(&inputs_file_path)?;
program.parse_inputs(&inputs_file_path, &inputs_file_string)?;
// Start the timer
let start = Instant::now();
let rng = &mut thread_rng();
let program_proof = create_random_proof(program, &parameters, rng).unwrap();
let program_proof = create_random_proof(program.clone(), &parameters, rng)?;
log::info!("Prover completed in {:?} milliseconds", start.elapsed().as_millis());
@ -55,6 +72,6 @@ impl CLI for ProveCommand {
log::info!("Completed program proving");
Ok(program_proof)
Ok((program, program_proof, prepared_verifying_key))
}
}

View File

@ -1,11 +1,7 @@
use crate::{
cli::*,
cli_types::*,
commands::{ProveCommand, SetupCommand},
errors::CLIError,
};
use crate::{cli::*, cli_types::*, commands::ProveCommand, errors::CLIError};
use snarkos_algorithms::snark::verify_proof;
use snarkos_curves::bls12_377::Bls12_377;
use clap::ArgMatches;
use std::time::{Duration, Instant};
@ -31,16 +27,16 @@ impl CLI for RunCommand {
#[cfg_attr(tarpaulin, skip)]
fn output(options: Self::Options) -> Result<(), CLIError> {
let (_program, _parameters, prepared_verifying_key) = SetupCommand::output(options)?;
let proof = ProveCommand::output(options)?;
let (program, proof, prepared_verifying_key) = ProveCommand::output(options)?;
let mut verifying = Duration::new(0, 0);
// let _inputs: Vec<_> = [1u32; 1].to_vec();
// fetch public inputs
let inputs: Vec<_> = program.get_public_inputs::<Bls12_377>().unwrap();
let start = Instant::now();
let is_success = verify_proof(&prepared_verifying_key, &proof, &[]).unwrap();
let is_success = verify_proof(&prepared_verifying_key, &proof, &inputs).unwrap();
verifying += start.elapsed();

View File

@ -57,6 +57,12 @@ impl From<leo_compiler::errors::CompilerError> for CLIError {
}
}
impl From<leo_inputs::errors::InputParserError> for CLIError {
fn from(error: leo_inputs::errors::InputParserError) -> Self {
CLIError::Crate("leo_inputs", format!("{}", error))
}
}
impl From<snarkos_errors::gadgets::SynthesisError> for CLIError {
fn from(error: snarkos_errors::gadgets::SynthesisError) -> Self {
CLIError::Crate("snarkos_errors", format!("{}", error))

56
leo/files/inputs.rs Normal file
View File

@ -0,0 +1,56 @@
//! The `inputs.leo` file.
use crate::{directories::inputs::INPUTS_DIRECTORY_NAME, errors::MainFileError};
use serde::Deserialize;
use std::{fs::File, io::Write, path::PathBuf};
pub static INPUTS_FILE_NAME: &str = "inputs.leo";
#[derive(Deserialize)]
pub struct InputsFile {
pub package_name: String,
}
impl InputsFile {
pub fn new(package_name: &str) -> Self {
Self {
package_name: package_name.to_string(),
}
}
pub fn exists_at(path: &PathBuf) -> bool {
let mut path = path.to_owned();
if path.is_dir() {
if !path.ends_with(INPUTS_DIRECTORY_NAME) {
path.push(PathBuf::from(INPUTS_DIRECTORY_NAME));
}
path.push(PathBuf::from(INPUTS_FILE_NAME));
}
path.exists()
}
pub fn write_to(self, path: &PathBuf) -> Result<(), MainFileError> {
let mut path = path.to_owned();
if path.is_dir() {
if !path.ends_with(INPUTS_DIRECTORY_NAME) {
path.push(PathBuf::from(INPUTS_DIRECTORY_NAME));
}
path.push(PathBuf::from(INPUTS_FILE_NAME));
}
let mut file = File::create(&path)?;
Ok(file.write_all(self.template().as_bytes())?)
}
fn template(&self) -> String {
format!(
r#"// The inputs for {}/src/main.leo
[main]
a: private u32 = 1;
b: public u32 = 2;
"#,
self.package_name
)
}
}

View File

@ -46,9 +46,9 @@ impl MainFile {
fn template(&self) -> String {
format!(
r#"// The '{}' main function.
function main() -> u32 {{
let a: u32 = 1 + 1;
return a
function main(a: private u32, b: public u32) -> u32 {{
let c: u32 = a + b;
return c
}}
"#,
self.package_name

View File

@ -1,6 +1,9 @@
pub mod checksum;
pub use self::checksum::*;
pub mod inputs;
pub use self::inputs::*;
pub mod gitignore;
pub use self::gitignore::*;

View File

@ -6,6 +6,7 @@ edition = "2018"
[dependencies]
leo-ast = { path = "../ast", version = "0.1.0" }
leo-inputs = { path = "../leo-inputs", version = "0.1.0" }
snarkos-errors = { path = "../../snarkOS/errors", version = "0.8.0" }
snarkos-models = { path = "../../snarkOS/models", version = "0.8.0" }

View File

@ -28,8 +28,8 @@ impl<'ast> From<AstFunctionInput<'ast>> for FunctionInput {
}
}
impl fmt::Display for FunctionInput {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
impl FunctionInput {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
// mut var: private bool
if self.mutable {
write!(f, "mut ")?;
@ -43,3 +43,15 @@ impl fmt::Display for FunctionInput {
write!(f, "{}", self._type)
}
}
impl fmt::Display for FunctionInput {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
impl fmt::Debug for FunctionInput {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}

View File

@ -1,31 +0,0 @@
use std::fmt;
#[derive(Clone, PartialEq, Eq)]
pub enum InputValue {
Integer(u128),
Field(String),
Group(String),
Boolean(bool),
Array(Vec<InputValue>),
}
impl fmt::Display for InputValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
InputValue::Integer(ref integer) => write!(f, "{}", integer),
InputValue::Field(ref field) => write!(f, "{}", field),
InputValue::Group(ref group) => write!(f, "{}", group),
InputValue::Boolean(ref bool) => write!(f, "{}", bool),
InputValue::Array(ref array) => {
write!(f, "[")?;
for (i, e) in array.iter().enumerate() {
write!(f, "{}", e)?;
if i < array.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
}
}

View File

@ -0,0 +1,70 @@
use crate::InputValue;
use leo_inputs::{types::IntegerType, InputParserError};
use snarkos_models::curves::{Field, PairingEngine};
use std::str::FromStr;
pub struct InputFields<E: PairingEngine>(pub Vec<E::Fr>);
impl<E: PairingEngine> InputFields<E> {
pub(crate) fn from_boolean(boolean: &bool) -> Self {
if *boolean {
Self(vec![E::Fr::one()])
} else {
Self(vec![E::Fr::zero()])
}
}
pub(crate) fn from_integer(type_: &IntegerType, integer: &u128) -> Self {
let bits: usize = match type_ {
IntegerType::U8Type(_) => 8,
IntegerType::U16Type(_) => 16,
IntegerType::U32Type(_) => 32,
IntegerType::U64Type(_) => 64,
IntegerType::U128Type(_) => 128,
};
let mut fields = vec![];
for i in 0..bits {
let boolean = (integer.to_le() >> i) & 1 == 1;
let mut boolean_fields = InputFields::<E>::from_boolean(&boolean);
fields.append(&mut boolean_fields.0);
}
Self(fields)
}
pub(crate) fn from_field(field: &str) -> Result<Self, InputParserError> {
let field = E::Fr::from_str(field).map_err(|_| InputParserError::ParseFieldError(field.to_string()))?;
Ok(Self(vec![field]))
}
pub(crate) fn from_group(group: &str) -> Result<Self, InputParserError> {
let s = group.trim();
let mut fields = vec![];
for substr in s.split(|c| c == '(' || c == ')' || c == ',' || c == ' ') {
if !substr.is_empty() {
let mut input_fields = InputFields::<E>::from_field(&substr)?;
fields.append(&mut input_fields.0);
}
}
Ok(Self(fields))
}
pub(crate) fn from_array(array: &Vec<InputValue>) -> Result<Self, InputParserError> {
let mut fields = vec![];
for input in array.iter() {
let mut input_fields = input.to_input_fields::<E>()?;
fields.append(&mut input_fields.0);
}
Ok(Self(fields))
}
}

View File

@ -0,0 +1,183 @@
use crate::InputFields;
use leo_inputs::{
errors::InputParserError,
expressions::{ArrayInitializerExpression, ArrayInlineExpression, Expression},
types::{ArrayType, DataType, IntegerType, Type},
values::{BooleanValue, FieldValue, GroupValue, NumberImplicitValue, NumberValue, Value},
};
use snarkos_models::curves::PairingEngine;
use std::fmt;
#[derive(Clone, PartialEq, Eq)]
pub enum InputValue {
Integer(IntegerType, u128),
Field(String),
Group(String),
Boolean(bool),
Array(Vec<InputValue>),
}
impl<'ast> InputValue {
fn from_boolean(boolean: BooleanValue<'ast>) -> Result<Self, InputParserError> {
let boolean = boolean.value.parse::<bool>()?;
Ok(InputValue::Boolean(boolean))
}
fn from_number(integer_type: IntegerType, number: NumberValue<'ast>) -> Result<Self, InputParserError> {
let integer = number.value.parse::<u128>()?;
Ok(InputValue::Integer(integer_type, integer))
}
fn from_group(group: GroupValue<'ast>) -> Self {
InputValue::Group(group.to_string())
}
fn from_field(field: FieldValue<'ast>) -> Self {
InputValue::Field(field.number.value)
}
fn from_implicit(data_type: DataType, implicit: NumberImplicitValue<'ast>) -> Result<Self, InputParserError> {
match data_type {
DataType::Boolean(_) => Err(InputParserError::IncompatibleTypes(
"bool".to_string(),
"implicit number".to_string(),
)),
DataType::Integer(integer_type) => InputValue::from_number(integer_type, implicit.number),
DataType::Group(_) => Ok(InputValue::Group(implicit.number.value)),
DataType::Field(_) => Ok(InputValue::Field(implicit.number.value)),
}
}
fn from_value(data_type: DataType, value: Value<'ast>) -> Result<Self, InputParserError> {
match (data_type, value) {
(DataType::Boolean(_), Value::Boolean(boolean)) => InputValue::from_boolean(boolean),
(DataType::Integer(integer_type), Value::Integer(integer)) => {
InputValue::from_number(integer_type, integer.number)
}
(DataType::Group(_), Value::Group(group)) => Ok(InputValue::from_group(group)),
(DataType::Field(_), Value::Field(field)) => Ok(InputValue::from_field(field)),
(data_type, Value::Implicit(implicit)) => InputValue::from_implicit(data_type, implicit),
(data_type, value) => Err(InputParserError::IncompatibleTypes(
data_type.to_string(),
value.to_string(),
)),
}
}
pub(crate) fn from_expression(type_: Type<'ast>, expression: Expression<'ast>) -> Result<Self, InputParserError> {
match (type_, expression) {
(Type::Basic(data_type), Expression::Value(value)) => InputValue::from_value(data_type, value),
(Type::Array(array_type), Expression::ArrayInline(inline)) => {
InputValue::from_array_inline(array_type, inline)
}
(Type::Array(array_type), Expression::ArrayInitializer(initializer)) => {
InputValue::from_array_initializer(array_type, initializer)
}
(type_, value) => Err(InputParserError::IncompatibleTypes(
type_.to_string(),
value.to_string(),
)),
}
}
pub(crate) fn from_array_inline(
mut array_type: ArrayType,
inline: ArrayInlineExpression,
) -> Result<Self, InputParserError> {
match array_type.next_dimension() {
Some(number) => {
let outer_dimension = number.value.parse::<usize>()?;
if outer_dimension != inline.expressions.len() {
return Err(InputParserError::InvalidArrayLength(
outer_dimension,
inline.expressions.len(),
));
}
}
None => return Err(InputParserError::UndefinedArrayDimension),
}
let inner_array_type = if array_type.dimensions.len() == 0 {
// this is a single array
Type::Basic(array_type._type)
} else {
Type::Array(array_type)
};
let mut values = vec![];
for expression in inline.expressions.into_iter() {
let value = InputValue::from_expression(inner_array_type.clone(), expression)?;
values.push(value)
}
Ok(InputValue::Array(values))
}
pub(crate) fn from_array_initializer(
mut array_type: ArrayType,
initializer: ArrayInitializerExpression,
) -> Result<Self, InputParserError> {
let initializer_count = initializer.count.value.parse::<usize>()?;
match array_type.next_dimension() {
Some(number) => {
let outer_dimension = number.value.parse::<usize>()?;
if outer_dimension != initializer_count {
return Err(InputParserError::InvalidArrayLength(outer_dimension, initializer_count));
}
}
None => return Err(InputParserError::UndefinedArrayDimension),
}
let inner_array_type = if array_type.dimensions.len() == 0 {
// this is a single array
Type::Basic(array_type._type)
} else {
Type::Array(array_type)
};
let mut values = vec![];
for _ in 0..initializer_count {
let value = InputValue::from_expression(inner_array_type.clone(), *initializer.expression.clone())?;
values.push(value)
}
Ok(InputValue::Array(values))
}
pub(crate) fn to_input_fields<E: PairingEngine>(&self) -> Result<InputFields<E>, InputParserError> {
match self {
InputValue::Boolean(boolean) => Ok(InputFields::from_boolean(boolean)),
InputValue::Integer(type_, number) => Ok(InputFields::from_integer(type_, number)),
InputValue::Group(group) => InputFields::from_group(group),
InputValue::Field(field) => InputFields::from_field(field),
InputValue::Array(array) => InputFields::from_array(array),
}
}
}
impl fmt::Display for InputValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
InputValue::Boolean(ref boolean) => write!(f, "{}", boolean),
InputValue::Integer(ref type_, ref number) => write!(f, "{}{:?}", number, type_),
InputValue::Group(ref group) => write!(f, "{}", group),
InputValue::Field(ref field) => write!(f, "{}", field),
InputValue::Array(ref array) => {
write!(f, "[")?;
for (i, e) in array.iter().enumerate() {
write!(f, "{}", e)?;
if i < array.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
}
}

View File

@ -0,0 +1,92 @@
use crate::{FunctionInput, InputValue};
use leo_inputs::{common::visibility::Visibility, files::File, InputParserError};
use leo_inputs::common::Private;
use snarkos_models::curves::PairingEngine;
#[derive(Clone)]
pub struct Inputs {
program_inputs: Vec<Option<InputValue>>,
public: Vec<InputValue>,
}
impl Inputs {
pub fn new() -> Self {
Self {
program_inputs: vec![],
public: vec![],
}
}
pub fn get_inputs(&self) -> Vec<Option<InputValue>> {
self.program_inputs.clone()
}
pub fn set_inputs(&mut self, inputs: Vec<Option<InputValue>>) {
self.program_inputs = inputs;
}
pub fn set_inputs_size(&mut self, size: usize) {
self.program_inputs = vec![None; size];
}
pub fn from_inputs_file(file: File, expected_inputs: Vec<FunctionInput>) -> Result<Self, InputParserError> {
let mut private = vec![];
let mut public = vec![];
for section in file.sections.into_iter() {
if section.header.name.value.eq("main") {
for input in &expected_inputs {
// find input with matching name
let matched_input = section.assignments.clone().into_iter().find(|assignment| {
let visibility = assignment
.parameter
.visibility
.as_ref()
.map_or(true, |visibility| visibility.eq(&Visibility::Private(Private {})));
// name match
assignment.parameter.variable.value.eq(&input.identifier.name)
// visibility match
&& visibility.eq(&input.private)
// type match
&& assignment.parameter.type_.to_string().eq(&input._type.to_string())
});
match matched_input {
Some(assignment) => {
let value = InputValue::from_expression(assignment.parameter.type_, assignment.expression)?;
if let Some(Visibility::Public(_)) = assignment.parameter.visibility {
// Collect public inputs here
public.push(value.clone());
}
// push value to vector
private.push(Some(value));
}
None => return Err(InputParserError::InputNotFound(input.to_string())),
}
}
}
}
Ok(Self {
program_inputs: private,
public,
})
}
pub fn get_public_inputs<E: PairingEngine>(&self) -> Result<Vec<E::Fr>, InputParserError> {
let mut input_vec = vec![];
for input in self.public.iter() {
// get fields
let mut input_fields = input.to_input_fields::<E>()?;
// push fields to input_vec
input_vec.append(&mut input_fields.0)
}
Ok(input_vec)
}
}

8
types/src/inputs/mod.rs Normal file
View File

@ -0,0 +1,8 @@
pub mod inputs;
pub use inputs::*;
pub mod input_fields;
pub use input_fields::*;
pub mod input_value;
pub use input_value::*;

View File

@ -87,7 +87,7 @@ impl Integer {
// Check that the input value is the correct type
let integer_option = match integer_value {
Some(input) => {
if let InputValue::Integer(integer) = input {
if let InputValue::Integer(_type_, integer) = input {
Some(integer)
} else {
return Err(IntegerError::InvalidInteger(input.to_string()));

View File

@ -19,8 +19,8 @@ pub use functions::*;
pub mod imports;
pub use imports::*;
pub mod input_value;
pub use input_value::*;
pub mod inputs;
pub use inputs::*;
pub mod integer;
pub use integer::*;

View File

@ -1,7 +1,7 @@
//! A typed Leo program consists of import, circuit, and function definitions.
//! Each defined type consists of typed statements and expressions.
use crate::{Circuit, Function, Identifier, Import, TestFunction};
use crate::{Circuit, Function, FunctionInput, Identifier, Import, TestFunction};
use leo_ast::files::File;
use std::collections::HashMap;
@ -10,7 +10,7 @@ use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct Program {
pub name: Identifier,
pub num_parameters: usize,
pub expected_inputs: Vec<FunctionInput>,
pub imports: Vec<Import>,
pub circuits: HashMap<Identifier, Circuit>,
pub functions: HashMap<Identifier, Function>,
@ -30,7 +30,7 @@ impl<'ast> Program {
let mut circuits = HashMap::new();
let mut functions = HashMap::new();
let mut tests = HashMap::new();
let mut num_parameters = 0usize;
let mut expected_inputs = vec![];
file.circuits.into_iter().for_each(|circuit| {
circuits.insert(Identifier::from(circuit.identifier.clone()), Circuit::from(circuit));
@ -49,12 +49,12 @@ impl<'ast> Program {
});
if let Some(main_function) = functions.get(&Identifier::new("main".into())) {
num_parameters = main_function.inputs.len();
expected_inputs = main_function.inputs.clone();
}
Self {
name: Identifier::new(name),
num_parameters,
expected_inputs,
imports,
circuits,
functions,
@ -67,7 +67,7 @@ impl Program {
pub fn new() -> Self {
Self {
name: Identifier::new("".into()),
num_parameters: 0,
expected_inputs: vec![],
imports: vec![],
circuits: HashMap::new(),
functions: HashMap::new(),