mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-25 03:04:13 +03:00
add core circuit errors
This commit is contained in:
parent
20fbf96784
commit
2a9d69f07f
@ -15,6 +15,7 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
@ -292,7 +292,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
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,
|
||||
|
@ -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<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
/// Call a default core circuit function
|
||||
pub fn enforce_core_function_call_expression<CS: ConstraintSystem<F>>(
|
||||
/// Call a default core circuit function with arguments
|
||||
pub fn enforce_core_circuit_call_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
expected_type: Option<Type>,
|
||||
function: String,
|
||||
core_circuit: String,
|
||||
arguments: Vec<Expression>,
|
||||
span: Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
@ -46,7 +46,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
}
|
||||
|
||||
// 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
|
@ -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::*;
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
mut cs: CS,
|
||||
arguments: Vec<Value>,
|
||||
_span: Span, // todo: return errors using `leo-typed` span
|
||||
) -> Vec<Value> {
|
||||
// The check evaluation gadget should have two arguments: seed and input
|
||||
if arguments.len() != 2 {
|
||||
unimplemented!("incorrect number of arguments")
|
||||
span: Span,
|
||||
) -> Result<Vec<Value>, 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<UInt8> 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<UInt8> {
|
||||
fn check_array_bytes(value: Value, size: usize, span: Span) -> Result<Vec<UInt8>, 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<UInt8> {
|
||||
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)
|
||||
}
|
||||
|
79
core/src/errors/core_circuit.rs
Normal file
79
core/src/errors/core_circuit.rs
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
// 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)
|
||||
// }
|
||||
// }
|
48
core/src/errors/leo_core.rs
Normal file
48
core/src/errors/leo_core.rs
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
@ -13,3 +13,12 @@
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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::*;
|
||||
|
@ -14,6 +14,9 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#[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<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
/// 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<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
cs: CS,
|
||||
function_name: String,
|
||||
circuit_name: String,
|
||||
arguments: Vec<Value>,
|
||||
span: Span, // TODO(collinc97): return errors using `leo-typed` span
|
||||
) -> Vec<Value> {
|
||||
// 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<Vec<Value>, 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)),
|
||||
})
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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<F: Field + PrimeField, CS: ConstraintSystem<F>>(cs: CS, arguments: Vec<Value>, span: Span) -> Vec<Value>;
|
||||
/// Call the gadget associated with this core circuit with arguments.
|
||||
/// Generate constraints on the given `ConstraintSystem`.
|
||||
fn call<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
cs: CS,
|
||||
arguments: Vec<Value>,
|
||||
span: Span,
|
||||
) -> Result<Vec<Value>, CoreCircuitError>;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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 {
|
||||
|
@ -15,7 +15,9 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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<Value>),
|
||||
Tuple(Vec<Value>),
|
||||
}
|
||||
|
||||
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::<Vec<_>>().join(", ");
|
||||
|
||||
write!(f, "[{}]", string)?;
|
||||
|
||||
Some("".to_owned())
|
||||
}
|
||||
Value::Tuple(values) => {
|
||||
let string = values.iter().map(|v| format!("{}", v)).collect::<Vec<_>>().join(", ");
|
||||
|
||||
write!(f, "[{}]", string)?;
|
||||
|
||||
Some("".to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
let string = string_option.unwrap_or("[input]".to_owned());
|
||||
|
||||
write!(f, "{}", string)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user