diff --git a/compiler/src/errors/expression.rs b/compiler/src/errors/expression.rs
index 47b4bd15e5..65b8c69bd5 100644
--- a/compiler/src/errors/expression.rs
+++ b/compiler/src/errors/expression.rs
@@ -15,6 +15,7 @@
// along with the Leo library. If not, see .
use crate::errors::{AddressError, BooleanError, FieldError, FunctionError, GroupError, IntegerError, ValueError};
+use leo_core::LeoCoreError;
use leo_typed::{Error as FormattedError, Identifier, Span};
use snarkos_errors::gadgets::SynthesisError;
@@ -43,6 +44,9 @@ pub enum ExpressionError {
#[error("{}", _0)]
IntegerError(#[from] IntegerError),
+ #[error("{}", _0)]
+ LeoCoreError(#[from] LeoCoreError),
+
#[error("{}", _0)]
ValueError(#[from] ValueError),
}
@@ -57,6 +61,7 @@ impl ExpressionError {
ExpressionError::FunctionError(error) => error.set_path(path),
ExpressionError::GroupError(error) => error.set_path(path),
ExpressionError::IntegerError(error) => error.set_path(path),
+ ExpressionError::LeoCoreError(error) => error.set_path(path),
ExpressionError::ValueError(error) => error.set_path(path),
}
}
diff --git a/compiler/src/expression/expression.rs b/compiler/src/expression/expression.rs
index f95139c045..3304c2725d 100644
--- a/compiler/src/expression/expression.rs
+++ b/compiler/src/expression/expression.rs
@@ -292,7 +292,7 @@ impl> ConstrainedProgram {
arguments,
span,
),
- Expression::CoreFunctionCall(function, arguments, span) => self.enforce_core_function_call_expression(
+ Expression::CoreFunctionCall(function, arguments, span) => self.enforce_core_circuit_call_expression(
cs,
file_scope,
function_scope,
diff --git a/compiler/src/expression/function/core_function.rs b/compiler/src/expression/function/core_circuit.rs
similarity index 90%
rename from compiler/src/expression/function/core_function.rs
rename to compiler/src/expression/function/core_circuit.rs
index 549ca8205a..6dbabbc5e7 100644
--- a/compiler/src/expression/function/core_function.rs
+++ b/compiler/src/expression/function/core_circuit.rs
@@ -16,7 +16,7 @@
use crate::{program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use crate::errors::{ExpressionError, FunctionError};
-use leo_core::call_core_function;
+use leo_core::call_core_circuit;
use leo_typed::{Expression, Span, Type};
use snarkos_models::{
curves::{Field, PrimeField},
@@ -24,14 +24,14 @@ use snarkos_models::{
};
impl> ConstrainedProgram {
- /// Call a default core circuit function
- pub fn enforce_core_function_call_expression>(
+ /// Call a default core circuit function with arguments
+ pub fn enforce_core_circuit_call_expression>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_type: Option,
- function: String,
+ core_circuit: String,
arguments: Vec,
span: Span,
) -> Result, ExpressionError> {
@@ -46,7 +46,7 @@ impl> ConstrainedProgram {
}
// Call the core function in `leo-core`
- let res = call_core_function(cs, function, argument_values, span.clone());
+ let res = call_core_circuit(cs, core_circuit, argument_values, span.clone())?;
// Convert the core function returns into constrained values
let returns = res
diff --git a/compiler/src/expression/function/mod.rs b/compiler/src/expression/function/mod.rs
index 354c610f5e..e8f769f2ae 100644
--- a/compiler/src/expression/function/mod.rs
+++ b/compiler/src/expression/function/mod.rs
@@ -16,8 +16,8 @@
//! Methods to enforce function call expressions in a compiled Leo program.
-pub mod core_function;
-pub use self::core_function::*;
+pub mod core_circuit;
+pub use self::core_circuit::*;
pub mod function;
pub use self::function::*;
diff --git a/core/src/circuits/unstable/blake2s.rs b/core/src/circuits/unstable/blake2s.rs
index 48809e30e7..72404784b5 100644
--- a/core/src/circuits/unstable/blake2s.rs
+++ b/core/src/circuits/unstable/blake2s.rs
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see .
-use crate::{CoreCircuit, Value};
+use crate::{CoreCircuit, CoreCircuitError, Value};
use leo_typed::{
Circuit,
@@ -42,9 +42,9 @@ use snarkos_models::{
pub const CORE_UNSTABLE_BLAKE2S_NAME: &str = "Blake2s";
#[derive(Clone, PartialEq, Eq)]
-pub struct Blake2sFunction {}
+pub struct Blake2sCircuit {}
-impl CoreCircuit for Blake2sFunction {
+impl CoreCircuit for Blake2sCircuit {
fn name() -> String {
CORE_UNSTABLE_BLAKE2S_NAME.to_owned()
}
@@ -110,39 +110,52 @@ impl CoreCircuit for Blake2sFunction {
}
}
+ /// Calls the native `Blake2sGadget` on the given constraint system with the given arguments
fn call>(
mut cs: CS,
arguments: Vec,
- _span: Span, // todo: return errors using `leo-typed` span
- ) -> Vec {
- // The check evaluation gadget should have two arguments: seed and input
- if arguments.len() != 2 {
- unimplemented!("incorrect number of arguments")
+ span: Span,
+ ) -> Result, CoreCircuitError> {
+ // The blake2s check evaluation gadget has two arguments: seed and input
+ let expected_length = 2usize;
+ let actual_length = arguments.len();
+
+ if expected_length != actual_length {
+ return Err(CoreCircuitError::arguments_length(expected_length, actual_length, span));
}
let seed_value = arguments[0].to_owned();
let input_value = arguments[1].to_owned();
- let seed = check_array_bytes(seed_value, 32);
- let input = check_array_bytes(input_value, 32);
+ let seed = check_array_bytes(seed_value, 32, span.clone())?;
+ let input = check_array_bytes(input_value, 32, span.clone())?;
+
+ // Call blake2s gadget
+ let digest =
+ Blake2sGadget::check_evaluation_gadget(cs.ns(|| "blake2s hash"), &seed[..], &input[..]).map_err(|e| {
+ CoreCircuitError::cannot_enforce("Blake2s check evaluation gadget".to_owned(), e, span.clone())
+ })?;
+
+ // Convert digest to bytes
+ let bytes = digest
+ .to_bytes(cs)
+ .map_err(|e| CoreCircuitError::cannot_enforce("Vec ToBytes".to_owned(), e, span.clone()))?;
- let res = Blake2sGadget::check_evaluation_gadget(cs.ns(|| "blake2s hash"), &seed[..], &input[..]).unwrap();
- let bytes = res.to_bytes(cs).unwrap();
let return_value = bytes.into_iter().map(|byte| Value::U8(byte)).collect();
// Return one array digest value
- vec![Value::Array(return_value)]
+ Ok(vec![Value::Array(return_value)])
}
}
-fn check_array_bytes(value: Value, size: usize) -> Vec {
+fn check_array_bytes(value: Value, size: usize, span: Span) -> Result, CoreCircuitError> {
let array_value = match value {
Value::Array(array) => array,
- _ => unimplemented!("expected array value"),
+ value => return Err(CoreCircuitError::invalid_array(value, span)),
};
- if array_value.len() != size {
- unimplemented!("expected array size of {}", size)
+ if size != array_value.len() {
+ return Err(CoreCircuitError::array_length(size, array_value.len(), span));
}
let mut array_bytes = vec![];
@@ -150,11 +163,11 @@ fn check_array_bytes(value: Value, size: usize) -> Vec {
for value in array_value {
let byte = match value {
Value::U8(u8) => u8,
- _ => unimplemented!("expected u8 byte"),
+ value => return Err(CoreCircuitError::invalid_array_bytes(value, span)),
};
array_bytes.push(byte)
}
- array_bytes
+ Ok(array_bytes)
}
diff --git a/core/src/errors/core_circuit.rs b/core/src/errors/core_circuit.rs
new file mode 100644
index 0000000000..0015132117
--- /dev/null
+++ b/core/src/errors/core_circuit.rs
@@ -0,0 +1,79 @@
+// Copyright (C) 2019-2020 Aleo Systems Inc.
+// This file is part of the Leo library.
+
+// The Leo library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// The Leo library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with the Leo library. If not, see .
+
+use crate::Value;
+use leo_typed::{Error as FormattedError, Span};
+
+use snarkos_errors::gadgets::SynthesisError;
+
+use std::path::PathBuf;
+
+#[derive(Debug, Error)]
+pub enum CoreCircuitError {
+ #[error("{}", _0)]
+ Error(#[from] FormattedError),
+}
+
+impl CoreCircuitError {
+ pub fn set_path(&mut self, path: PathBuf) {
+ match self {
+ CoreCircuitError::Error(error) => error.set_path(path),
+ }
+ }
+
+ fn new_from_span(message: String, span: Span) -> Self {
+ CoreCircuitError::Error(FormattedError::new_from_span(message, span))
+ }
+
+ pub fn arguments_length(expected: usize, actual: usize, span: Span) -> Self {
+ let message = format!("Core circuit expected {} arguments, found {}", expected, actual);
+
+ CoreCircuitError::new_from_span(message, span)
+ }
+
+ pub fn array_length(expected: usize, actual: usize, span: Span) -> Self {
+ let message = format!(
+ "Core circuit expected an array of length {}, found an array of length {}",
+ expected, actual
+ );
+
+ CoreCircuitError::new_from_span(message, span)
+ }
+
+ pub fn cannot_enforce(operation: String, error: SynthesisError, span: Span) -> Self {
+ let message = format!(
+ "The gadget operation `{}` failed due to synthesis error `{:?}`",
+ operation, error,
+ );
+
+ Self::new_from_span(message, span)
+ }
+
+ pub fn invalid_array(actual: Value, span: Span) -> Self {
+ let message = format!("Core circuit expected an array argument, found `{}`", actual);
+
+ Self::new_from_span(message, span)
+ }
+
+ pub fn invalid_array_bytes(actual: Value, span: Span) -> Self {
+ let message = format!(
+ "Core circuit expected an array of UInt8 gadgets, found an array of `{}`",
+ actual
+ );
+
+ Self::new_from_span(message, span)
+ }
+}
diff --git a/core/src/errors/core_package.rs b/core/src/errors/core_package.rs
index e69de29bb2..22df9a52ce 100644
--- a/core/src/errors/core_package.rs
+++ b/core/src/errors/core_package.rs
@@ -0,0 +1,42 @@
+// Copyright (C) 2019-2020 Aleo Systems Inc.
+// This file is part of the Leo library.
+
+// The Leo library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// The Leo library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with the Leo library. If not, see .
+// use leo_typed::{Error as FormattedError, Span};
+//
+// use std::path::PathBuf;
+//
+// #[derive(Debug, Error)]
+// pub enum LeoCoreError {
+// #[error("{}", _0)]
+// Error(#[from] FormattedError),
+// }
+//
+// impl LeoCoreError {
+// pub fn set_path(&mut self, path: PathBuf) {
+// match self {
+// LeoCoreError::Error(error) => error.set_path(path)
+// }
+// }
+//
+// fn new_from_span(message: String, span: Span) -> Self {
+// LeoCoreError::Error(FormattedError::new_from_span(message, span))
+// }
+//
+// pub fn undefined_core_circuit(circuit_name: String, span: Span) -> Self {
+// let message = format!("Core circuit `{}` not found in `leo-core`", circuit_name);
+//
+// Self::new_from_span(message, span)
+// }
+// }
diff --git a/core/src/errors/leo_core.rs b/core/src/errors/leo_core.rs
new file mode 100644
index 0000000000..016b049663
--- /dev/null
+++ b/core/src/errors/leo_core.rs
@@ -0,0 +1,48 @@
+// Copyright (C) 2019-2020 Aleo Systems Inc.
+// This file is part of the Leo library.
+
+// The Leo library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// The Leo library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with the Leo library. If not, see .
+
+use crate::CoreCircuitError;
+use leo_typed::{Error as FormattedError, Span};
+
+use std::path::PathBuf;
+
+#[derive(Debug, Error)]
+pub enum LeoCoreError {
+ #[error("{}", _0)]
+ CoreCircuit(#[from] CoreCircuitError),
+
+ #[error("{}", _0)]
+ Error(#[from] FormattedError),
+}
+
+impl LeoCoreError {
+ pub fn set_path(&mut self, path: PathBuf) {
+ match self {
+ LeoCoreError::CoreCircuit(error) => error.set_path(path),
+ LeoCoreError::Error(error) => error.set_path(path),
+ }
+ }
+
+ fn new_from_span(message: String, span: Span) -> Self {
+ LeoCoreError::Error(FormattedError::new_from_span(message, span))
+ }
+
+ pub fn undefined_core_circuit(circuit_name: String, span: Span) -> Self {
+ let message = format!("Core circuit `{}` not found in `leo-core`", circuit_name);
+
+ Self::new_from_span(message, span)
+ }
+}
diff --git a/core/src/errors/mod.rs b/core/src/errors/mod.rs
index 600f61b496..a4aed5fa7a 100644
--- a/core/src/errors/mod.rs
+++ b/core/src/errors/mod.rs
@@ -13,3 +13,12 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see .
+
+pub mod core_circuit;
+pub use self::core_circuit::*;
+
+pub mod core_package;
+pub use self::core_package::*;
+
+pub mod leo_core;
+pub use self::leo_core::*;
diff --git a/core/src/lib.rs b/core/src/lib.rs
index 88240d79ab..0f61b28595 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -14,6 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see .
+#[macro_use]
+extern crate thiserror;
+
pub mod circuits;
pub use self::circuits::*;
@@ -30,17 +33,17 @@ use snarkos_models::{
gadgets::r1cs::ConstraintSystem,
};
-/// Calls a core function by it's given name.
-/// This function should be called by the compiler when enforcing the result of calling a core circuit function.
-pub fn call_core_function>(
+/// Calls a core circuit by it's given name.
+/// This function should be called by the compiler when enforcing a core circuit function expression.
+pub fn call_core_circuit>(
cs: CS,
- function_name: String,
+ circuit_name: String,
arguments: Vec,
- span: Span, // TODO(collinc97): return errors using `leo-typed` span
-) -> Vec {
- // Match core function name
- match function_name.as_str() {
- CORE_UNSTABLE_BLAKE2S_NAME => Blake2sFunction::call(cs, arguments, span),
- _ => unimplemented!("core function {} unimplemented", function_name),
- }
+ span: Span,
+) -> Result, LeoCoreError> {
+ // Match core circuit name
+ Ok(match circuit_name.as_str() {
+ CORE_UNSTABLE_BLAKE2S_NAME => Blake2sCircuit::call(cs, arguments, span)?,
+ _ => return Err(LeoCoreError::undefined_core_circuit(circuit_name, span)),
+ })
}
diff --git a/core/src/types/core_circuit.rs b/core/src/types/core_circuit.rs
index 18d88ed36f..e4984c5837 100644
--- a/core/src/types/core_circuit.rs
+++ b/core/src/types/core_circuit.rs
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see .
-use crate::Value;
+use crate::{CoreCircuitError, Value};
use leo_typed::{Circuit, Identifier, Span};
use snarkos_models::{
@@ -30,7 +30,11 @@ pub trait CoreCircuit {
/// Return the abstract syntax tree representation of the core circuit for compiler parsing.
fn ast(circuit_name: Identifier, span: Span) -> Circuit;
- /// Call the gadget associated with this core circuit.
- /// Generate constraints on the given `ConstraintSystem` and pass in `CoreFunctionArgument`s
- fn call>(cs: CS, arguments: Vec, span: Span) -> Vec;
+ /// Call the gadget associated with this core circuit with arguments.
+ /// Generate constraints on the given `ConstraintSystem`.
+ fn call>(
+ cs: CS,
+ arguments: Vec,
+ span: Span,
+ ) -> Result, CoreCircuitError>;
}
diff --git a/core/src/types/core_package.rs b/core/src/types/core_package.rs
index 11add5a408..e58efb5814 100644
--- a/core/src/types/core_package.rs
+++ b/core/src/types/core_package.rs
@@ -15,7 +15,7 @@
// along with the Leo library. If not, see .
use crate::{
- unstable::blake2s::{Blake2sFunction, CORE_UNSTABLE_BLAKE2S_NAME},
+ unstable::blake2s::{Blake2sCircuit, CORE_UNSTABLE_BLAKE2S_NAME},
CoreCircuit,
CoreSymbolList,
};
@@ -72,7 +72,7 @@ impl CorePackage {
let circuit = if self.unstable {
// match unstable core circuit
match symbol_name {
- CORE_UNSTABLE_BLAKE2S_NAME => Blake2sFunction::ast(symbol.symbol.clone(), span),
+ CORE_UNSTABLE_BLAKE2S_NAME => Blake2sCircuit::ast(symbol.symbol.clone(), span),
_ => unimplemented!("unstable core circuit `{}` not implemented", symbol_name),
}
} else {
diff --git a/core/src/types/value.rs b/core/src/types/value.rs
index 94722314f4..1a511e3ec0 100644
--- a/core/src/types/value.rs
+++ b/core/src/types/value.rs
@@ -15,7 +15,9 @@
// along with the Leo library. If not, see .
use leo_gadgets::signed_integer::*;
+
use snarkos_models::gadgets::utilities::{boolean::Boolean, uint::*};
+use std::fmt;
/// An intermediate value format that can be converted into a `ConstrainedValue` for the compiler
/// TODO(collinc97): implement other constrained values
@@ -38,3 +40,39 @@ pub enum Value {
Array(Vec),
Tuple(Vec),
}
+
+impl fmt::Display for Value {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let string_option = match self {
+ Value::Boolean(value) => value.get_value().map(|v| v.to_string()),
+ Value::U8(value) => value.value.map(|v| v.to_string()),
+ Value::U16(value) => value.value.map(|v| v.to_string()),
+ Value::U32(value) => value.value.map(|v| v.to_string()),
+ Value::U64(value) => value.value.map(|v| v.to_string()),
+ Value::U128(value) => value.value.map(|v| v.to_string()),
+ Value::I8(value) => value.value.map(|v| v.to_string()),
+ Value::I16(value) => value.value.map(|v| v.to_string()),
+ Value::I32(value) => value.value.map(|v| v.to_string()),
+ Value::I64(value) => value.value.map(|v| v.to_string()),
+ Value::I128(value) => value.value.map(|v| v.to_string()),
+ Value::Array(values) => {
+ let string = values.iter().map(|v| format!("{}", v)).collect::>().join(", ");
+
+ write!(f, "[{}]", string)?;
+
+ Some("".to_owned())
+ }
+ Value::Tuple(values) => {
+ let string = values.iter().map(|v| format!("{}", v)).collect::>().join(", ");
+
+ write!(f, "[{}]", string)?;
+
+ Some("".to_owned())
+ }
+ };
+
+ let string = string_option.unwrap_or("[input]".to_owned());
+
+ write!(f, "{}", string)
+ }
+}