mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-23 23:23:50 +03:00
make core function arguments and returns generic
This commit is contained in:
parent
3d3a093f2a
commit
32c85720be
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1262,6 +1262,7 @@ dependencies = [
|
||||
name = "leo-core"
|
||||
version = "1.0.1"
|
||||
dependencies = [
|
||||
"leo-gadgets",
|
||||
"leo-typed",
|
||||
"rand",
|
||||
"rand_xorshift",
|
||||
|
@ -106,6 +106,12 @@ impl FunctionError {
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn return_argument_type(expected: String, actual: String, span: Span) -> Self {
|
||||
let message = format!("Expected function return type `{}`, found `{}`", expected, actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn input_not_found(expected: String, span: Span) -> Self {
|
||||
let message = format!("main function input {} not found", expected);
|
||||
|
||||
|
@ -292,13 +292,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
arguments,
|
||||
span,
|
||||
),
|
||||
Expression::CoreFunctionCall(function, arguments) => self.enforce_core_function_call_expression(
|
||||
Expression::CoreFunctionCall(function, arguments, span) => self.enforce_core_function_call_expression(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type,
|
||||
function,
|
||||
arguments,
|
||||
span,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -13,44 +13,65 @@
|
||||
|
||||
// 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::{program::ConstrainedProgram, value::ConstrainedValue, GroupType, Integer};
|
||||
use crate::{program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
|
||||
use crate::errors::ExpressionError;
|
||||
use leo_core::{call_core_function, CoreFunctionArgument};
|
||||
use leo_typed::{Expression, Type};
|
||||
use crate::errors::{ExpressionError, FunctionError};
|
||||
use leo_core::call_core_function;
|
||||
use leo_typed::{Expression, Span, Type};
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::r1cs::ConstraintSystem,
|
||||
};
|
||||
|
||||
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>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
_expected_type: Option<Type>,
|
||||
expected_type: Option<Type>,
|
||||
function: String,
|
||||
arguments: Vec<Expression>,
|
||||
span: Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
// Get the value of each core function argument
|
||||
let mut argument_values = vec![];
|
||||
for argument in arguments.into_iter() {
|
||||
let argument_value =
|
||||
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), None, argument)?;
|
||||
let core_function_argument = CoreFunctionArgument(argument_value.to_value());
|
||||
let core_function_argument = argument_value.to_value();
|
||||
|
||||
argument_values.push(core_function_argument);
|
||||
}
|
||||
|
||||
// Call the core function in `leo-core`
|
||||
let res = call_core_function(cs, function, argument_values);
|
||||
let res = call_core_function(cs, function, argument_values, span.clone());
|
||||
|
||||
let array = res
|
||||
// Convert the core function returns into constrained values
|
||||
let returns = res
|
||||
.into_iter()
|
||||
.map(|uint| ConstrainedValue::Integer(Integer::U8(uint)))
|
||||
.collect();
|
||||
.map(|value| ConstrainedValue::from(value))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
return Ok(ConstrainedValue::Array(array));
|
||||
let return_value = if returns.len() == 1 {
|
||||
// The function has a single return
|
||||
returns[0].clone()
|
||||
} else {
|
||||
// The function has multiple returns
|
||||
ConstrainedValue::Tuple(returns)
|
||||
};
|
||||
|
||||
// Check that function returns expected type
|
||||
if let Some(expected) = expected_type {
|
||||
let actual = return_value.to_type(span.clone())?;
|
||||
if expected.ne(&actual) {
|
||||
return Err(ExpressionError::FunctionError(Box::new(
|
||||
FunctionError::return_argument_type(expected.to_string(), actual.to_string(), span),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(return_value);
|
||||
}
|
||||
}
|
@ -16,5 +16,8 @@
|
||||
|
||||
//! Methods to enforce function call expressions in a compiled Leo program.
|
||||
|
||||
pub mod core_function;
|
||||
pub use self::core_function::*;
|
||||
|
||||
pub mod function;
|
||||
pub use self::function::*;
|
||||
|
@ -16,9 +16,6 @@
|
||||
|
||||
//! Methods to enforce constraints on functions in a compiled Leo program.
|
||||
|
||||
pub mod core_function;
|
||||
pub use self::core_function::*;
|
||||
|
||||
pub mod input;
|
||||
pub use self::input::*;
|
||||
|
||||
|
@ -35,7 +35,7 @@ impl ImportParser {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, file_name: String, program: Program) {
|
||||
pub(crate) fn insert_import(&mut self, file_name: String, program: Program) {
|
||||
// todo: handle conflicting versions for duplicate imports here
|
||||
let _res = self.imports.insert(file_name, program);
|
||||
}
|
||||
@ -44,11 +44,11 @@ impl ImportParser {
|
||||
let _res = self.core_packages.push(package.clone());
|
||||
}
|
||||
|
||||
pub fn get(&self, file_name: &String) -> Option<&Program> {
|
||||
pub fn get_import(&self, file_name: &String) -> Option<&Program> {
|
||||
self.imports.get(file_name)
|
||||
}
|
||||
|
||||
pub fn get_core_packages(&self) -> &Vec<Package> {
|
||||
pub fn core_packages(&self) -> &Vec<Package> {
|
||||
&self.core_packages
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,7 @@ impl ImportParser {
|
||||
.into_string()
|
||||
.unwrap(); // the file exists so these will not fail
|
||||
|
||||
self.insert(file_name, program);
|
||||
self.insert_import(file_name, program);
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
@ -117,7 +117,7 @@ impl ImportParser {
|
||||
.into_string()
|
||||
.unwrap(); // the file exists so these will not fail
|
||||
|
||||
self.insert(file_name, program);
|
||||
self.insert_import(file_name, program);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
) -> Result<(), ImportError> {
|
||||
// Fetch core dependencies
|
||||
let core_dependency = imported_programs
|
||||
.get_core_packages()
|
||||
.core_packages()
|
||||
.iter()
|
||||
.find(|package| import.package.eq(package));
|
||||
|
||||
@ -43,7 +43,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
for (package, symbol) in imported_symbols.symbols {
|
||||
// Find imported program
|
||||
let program = imported_programs
|
||||
.get(&package)
|
||||
.get_import(&package)
|
||||
.ok_or(ImportError::unknown_package(import.package.name.clone()))?;
|
||||
|
||||
// Parse imported program
|
||||
|
@ -26,6 +26,7 @@ use crate::{
|
||||
GroupType,
|
||||
Integer,
|
||||
};
|
||||
use leo_core::Value;
|
||||
use leo_typed::{Circuit, Function, GroupValue, Identifier, Span, Type};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
@ -33,7 +34,7 @@ use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{
|
||||
r1cs::ConstraintSystem,
|
||||
utilities::{boolean::Boolean, eq::ConditionalEqGadget, select::CondSelectGadget, uint::UInt8},
|
||||
utilities::{boolean::Boolean, eq::ConditionalEqGadget, select::CondSelectGadget},
|
||||
},
|
||||
};
|
||||
use std::fmt;
|
||||
@ -137,24 +138,34 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
||||
})
|
||||
}
|
||||
|
||||
// Hardcode to value for blake2s
|
||||
pub(crate) fn to_value(&self) -> Vec<UInt8> {
|
||||
match self {
|
||||
/// Returns the `ConstrainedValue` in intermediate `Value` format (for core circuits)
|
||||
pub(crate) fn to_value(&self) -> Value {
|
||||
match self.clone() {
|
||||
ConstrainedValue::Boolean(boolean) => Value::Boolean(boolean),
|
||||
ConstrainedValue::Integer(integer) => match integer {
|
||||
Integer::U8(u8) => vec![u8.clone()],
|
||||
_ => vec![],
|
||||
Integer::U8(u8) => Value::U8(u8),
|
||||
Integer::U16(u16) => Value::U16(u16),
|
||||
Integer::U32(u32) => Value::U32(u32),
|
||||
Integer::U64(u64) => Value::U64(u64),
|
||||
Integer::U128(u128) => Value::U128(u128),
|
||||
|
||||
Integer::I8(i8) => Value::I8(i8),
|
||||
Integer::I16(i16) => Value::I16(i16),
|
||||
Integer::I32(i32) => Value::I32(i32),
|
||||
Integer::I64(i64) => Value::I64(i64),
|
||||
Integer::I128(i128) => Value::I128(i128),
|
||||
},
|
||||
ConstrainedValue::Array(array) => {
|
||||
let mut value = vec![];
|
||||
let array_value = array.into_iter().map(|element| element.to_value()).collect();
|
||||
|
||||
for element in array {
|
||||
let values = &mut element.to_value();
|
||||
value.append(values);
|
||||
}
|
||||
|
||||
value
|
||||
Value::Array(array_value)
|
||||
}
|
||||
_ => vec![],
|
||||
ConstrainedValue::Tuple(tuple) => {
|
||||
let tuple_value = tuple.into_iter().map(|element| element.to_value()).collect();
|
||||
|
||||
Value::Tuple(tuple_value)
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -518,3 +529,35 @@ impl<F: Field + PrimeField, G: GroupType<F>> CondSelectGadget<F> for Constrained
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> From<Value> for ConstrainedValue<F, G> {
|
||||
fn from(v: Value) -> Self {
|
||||
match v {
|
||||
Value::Boolean(boolean) => ConstrainedValue::Boolean(boolean),
|
||||
Value::U8(u8) => ConstrainedValue::Integer(Integer::U8(u8)),
|
||||
Value::U16(u16) => ConstrainedValue::Integer(Integer::U16(u16)),
|
||||
Value::U32(u32) => ConstrainedValue::Integer(Integer::U32(u32)),
|
||||
Value::U64(u64) => ConstrainedValue::Integer(Integer::U64(u64)),
|
||||
Value::U128(u128) => ConstrainedValue::Integer(Integer::U128(u128)),
|
||||
|
||||
Value::I8(i8) => ConstrainedValue::Integer(Integer::I8(i8)),
|
||||
Value::I16(i16) => ConstrainedValue::Integer(Integer::I16(i16)),
|
||||
Value::I32(i32) => ConstrainedValue::Integer(Integer::I32(i32)),
|
||||
Value::I64(i64) => ConstrainedValue::Integer(Integer::I64(i64)),
|
||||
Value::I128(i128) => ConstrainedValue::Integer(Integer::I128(i128)),
|
||||
|
||||
Value::Array(array) => ConstrainedValue::Array(
|
||||
array
|
||||
.into_iter()
|
||||
.map(|element| ConstrainedValue::from(element))
|
||||
.collect(),
|
||||
),
|
||||
Value::Tuple(tuple) => ConstrainedValue::Tuple(
|
||||
tuple
|
||||
.into_iter()
|
||||
.map(|element| ConstrainedValue::from(element))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,10 @@ include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
|
||||
license = "GPL-3.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies.leo-gadgets]
|
||||
path = "../gadgets"
|
||||
version = "1.0.3"
|
||||
|
||||
[dependencies.leo-typed]
|
||||
path = "../typed"
|
||||
version = "1.0.3"
|
||||
|
@ -1,51 +0,0 @@
|
||||
// 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::CoreFunctionArgument;
|
||||
|
||||
use snarkos_gadgets::algorithms::prf::Blake2sGadget;
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{
|
||||
algorithms::PRFGadget,
|
||||
r1cs::ConstraintSystem,
|
||||
utilities::{uint::UInt8, ToBytesGadget},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Blake2sFunction {}
|
||||
|
||||
impl Blake2sFunction {
|
||||
pub fn hash<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
mut cs: CS,
|
||||
arguments: Vec<CoreFunctionArgument>,
|
||||
//_span: Span // todo: return errors using `leo-typed` span
|
||||
) -> Vec<UInt8> {
|
||||
// The check evaluation gadget should have two arguments: seed and input
|
||||
if arguments.len() != 2 {
|
||||
println!("incorrect number of arguments")
|
||||
}
|
||||
|
||||
let seed = &arguments[0].0[..];
|
||||
let input = &arguments[1].0[..];
|
||||
|
||||
let res = Blake2sGadget::check_evaluation_gadget(cs.ns(|| "blake2s hash"), seed, input).unwrap();
|
||||
let bytes = res.to_bytes(cs).unwrap();
|
||||
// println!("output {:?}", res.to_bytes(cs).unwrap().len());
|
||||
bytes
|
||||
}
|
||||
}
|
33
core/src/core_circuit.rs
Normal file
33
core/src/core_circuit.rs
Normal file
@ -0,0 +1,33 @@
|
||||
// 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::{Circuit, Identifier, Span};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::r1cs::ConstraintSystem,
|
||||
};
|
||||
|
||||
/// A core circuit type, accessible to all Leo programs by default
|
||||
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>;
|
||||
}
|
@ -13,5 +13,3 @@
|
||||
|
||||
// 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 hash;
|
179
core/src/lib.rs
179
core/src/lib.rs
@ -14,28 +14,28 @@
|
||||
// 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::blake2s::unstable::hash::Blake2sFunction;
|
||||
use leo_typed::{
|
||||
Circuit,
|
||||
CircuitMember,
|
||||
Expression,
|
||||
Function,
|
||||
FunctionInput,
|
||||
Identifier,
|
||||
ImportSymbol,
|
||||
InputVariable,
|
||||
IntegerType,
|
||||
Package,
|
||||
PackageAccess,
|
||||
Statement,
|
||||
Type,
|
||||
};
|
||||
pub mod core_circuit;
|
||||
pub use self::core_circuit::*;
|
||||
|
||||
pub mod errors;
|
||||
pub use self::errors::*;
|
||||
|
||||
pub mod unstable;
|
||||
pub use self::unstable::*;
|
||||
|
||||
use crate::unstable::blake2s::Blake2sFunction;
|
||||
use leo_gadgets::signed_integer::*;
|
||||
use leo_typed::{Circuit, Identifier, ImportSymbol, Package, PackageAccess, Span};
|
||||
|
||||
pub mod blake2s;
|
||||
pub use self::blake2s::*;
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{r1cs::ConstraintSystem, utilities::uint::UInt8},
|
||||
gadgets::{
|
||||
r1cs::ConstraintSystem,
|
||||
utilities::{
|
||||
boolean::Boolean,
|
||||
uint::{UInt128, UInt16, UInt32, UInt64, UInt8},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static UNSTABLE_CORE_PACKAGE_KEYWORD: &str = "unstable";
|
||||
@ -58,17 +58,14 @@ impl CorePackage {
|
||||
}
|
||||
|
||||
// Set the `unstable` flag to true if we are importing an unstable core package
|
||||
pub(crate) fn set_unstable(&mut self, identifier: &Identifier) {
|
||||
if identifier.name.eq(UNSTABLE_CORE_PACKAGE_KEYWORD) {
|
||||
self.unstable = true;
|
||||
}
|
||||
pub(crate) fn set_unstable(&mut self) {
|
||||
self.unstable = true;
|
||||
}
|
||||
|
||||
// Recursively set all symbols we are importing from a core package
|
||||
pub(crate) fn set_symbols(&mut self, access: PackageAccess) {
|
||||
match access {
|
||||
PackageAccess::SubPackage(package) => {
|
||||
self.set_unstable(&package.name);
|
||||
self.set_symbols(package.access);
|
||||
}
|
||||
PackageAccess::Star(_) => unimplemented!("cannot import star from core package"),
|
||||
@ -84,64 +81,14 @@ impl CorePackage {
|
||||
// Resolve import symbols into core circuits and store them in the program context
|
||||
pub(crate) fn append_symbols(&self, symbols: &mut CoreSymbolList) {
|
||||
for symbol in &self.symbols {
|
||||
//todo: resolve symbol alias if any
|
||||
let name = symbol.symbol.name.clone();
|
||||
// take the alias if it is present
|
||||
let id = symbol.alias.clone().unwrap_or(symbol.symbol.clone());
|
||||
|
||||
let name = id.name.clone();
|
||||
let span = symbol.span.clone();
|
||||
|
||||
/* Hardcode blake2s circuit for now
|
||||
* circuit Blake2s {
|
||||
* static function hash(seed: [u8; 32], message: [u8; 32]) -> [u8; 32] {
|
||||
* // call `check_eval_gadget` in snarkOS
|
||||
* return check_eval_gadget(seed, message)
|
||||
* }
|
||||
*/
|
||||
let blake2s_circuit = Circuit {
|
||||
circuit_name: symbol.symbol.clone(),
|
||||
members: vec![CircuitMember::CircuitFunction(
|
||||
true, // static function
|
||||
Function {
|
||||
identifier: Identifier {
|
||||
name: "hash".to_owned(),
|
||||
span: span.clone(),
|
||||
},
|
||||
input: vec![
|
||||
InputVariable::FunctionInput(FunctionInput {
|
||||
identifier: Identifier {
|
||||
name: "seed".to_owned(),
|
||||
span: span.clone(),
|
||||
},
|
||||
mutable: false,
|
||||
type_: Type::Array(Box::new(Type::IntegerType(IntegerType::U8)), vec![32usize]),
|
||||
span: span.clone(),
|
||||
}),
|
||||
InputVariable::FunctionInput(FunctionInput {
|
||||
identifier: Identifier {
|
||||
name: "message".to_owned(),
|
||||
span: span.clone(),
|
||||
},
|
||||
mutable: false,
|
||||
type_: Type::Array(Box::new(Type::IntegerType(IntegerType::U8)), vec![32usize]),
|
||||
span: span.clone(),
|
||||
}),
|
||||
],
|
||||
returns: Some(Type::Array(Box::new(Type::IntegerType(IntegerType::U8)), vec![32usize])),
|
||||
statements: vec![Statement::Return(
|
||||
Expression::CoreFunctionCall("core_blake2s_unstable".to_owned(), vec![
|
||||
Expression::Identifier(Identifier {
|
||||
name: "seed".to_owned(),
|
||||
span: span.clone(),
|
||||
}),
|
||||
Expression::Identifier(Identifier {
|
||||
name: "message".to_owned(),
|
||||
span: span.clone(),
|
||||
}),
|
||||
]),
|
||||
span.clone(),
|
||||
)],
|
||||
span: span.clone(),
|
||||
},
|
||||
)],
|
||||
};
|
||||
// todo: remove hardcoded blake2s circuit
|
||||
let blake2s_circuit = Blake2sFunction::ast(symbol.symbol.clone(), span);
|
||||
|
||||
symbols.push(name, blake2s_circuit)
|
||||
}
|
||||
@ -189,23 +136,41 @@ impl CorePackageList {
|
||||
pub fn from_package_access(access: PackageAccess) -> Self {
|
||||
let mut new = Self::new();
|
||||
|
||||
match access {
|
||||
PackageAccess::Symbol(_symbol) => unimplemented!("cannot import a symbol directly from Leo core"),
|
||||
PackageAccess::Multiple(_) => unimplemented!("multiple imports not yet implemented for Leo core"),
|
||||
PackageAccess::SubPackage(package) => {
|
||||
let core_package = CorePackage::from(*package);
|
||||
|
||||
new.push(core_package);
|
||||
}
|
||||
PackageAccess::Star(_) => unimplemented!("cannot import star from Leo core"),
|
||||
}
|
||||
package_access_helper(&mut new, access, false);
|
||||
|
||||
new
|
||||
}
|
||||
}
|
||||
|
||||
/// List of imported core function symbols and methods
|
||||
fn package_access_helper(list: &mut CorePackageList, access: PackageAccess, is_unstable: bool) {
|
||||
match access {
|
||||
PackageAccess::Symbol(_symbol) => unimplemented!("cannot import a symbol directly from Leo core"),
|
||||
PackageAccess::Multiple(core_functions) => {
|
||||
for access in core_functions {
|
||||
package_access_helper(list, access, is_unstable);
|
||||
}
|
||||
}
|
||||
PackageAccess::SubPackage(package) => {
|
||||
// Set the `unstable` flag to true if we are importing an unstable core package
|
||||
if package.name.name.eq(UNSTABLE_CORE_PACKAGE_KEYWORD) {
|
||||
package_access_helper(list, package.access, true);
|
||||
} else {
|
||||
let mut core_package = CorePackage::from(*package);
|
||||
|
||||
if is_unstable {
|
||||
core_package.set_unstable()
|
||||
}
|
||||
|
||||
list.push(core_package);
|
||||
}
|
||||
}
|
||||
PackageAccess::Star(_) => unimplemented!("cannot import star from Leo core"),
|
||||
}
|
||||
}
|
||||
|
||||
/// List of imported core function circuits
|
||||
pub struct CoreSymbolList {
|
||||
/// [(circuit_name, circuit_struct)]
|
||||
symbols: Vec<(String, Circuit)>,
|
||||
}
|
||||
|
||||
@ -223,23 +188,43 @@ impl CoreSymbolList {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CoreFunctionArgument(pub Vec<UInt8>);
|
||||
|
||||
/// 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>>(
|
||||
cs: CS,
|
||||
function_name: String,
|
||||
arguments: Vec<CoreFunctionArgument>,
|
||||
//_span: Span // todo: return errors using `leo-typed` span
|
||||
) -> Vec<UInt8> {
|
||||
arguments: Vec<Value>,
|
||||
span: Span, // todo: return errors using `leo-typed` span
|
||||
) -> Vec<Value> {
|
||||
// Match core function name here
|
||||
if function_name.ne("core_blake2s_unstable") {
|
||||
// todo: convert this to a real error
|
||||
println!("core dne error");
|
||||
}
|
||||
// Hardcode blake2s core function call
|
||||
let res = Blake2sFunction::hash(cs, arguments);
|
||||
let res = Blake2sFunction::call(cs, arguments, span);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// An intermediate value format that can be converted into a `ConstrainedValue` for the compiler
|
||||
/// Todo: implement other constrained values
|
||||
#[derive(Clone)]
|
||||
pub enum Value {
|
||||
Boolean(Boolean),
|
||||
|
||||
U8(UInt8),
|
||||
U16(UInt16),
|
||||
U32(UInt32),
|
||||
U64(UInt64),
|
||||
U128(UInt128),
|
||||
|
||||
I8(Int8),
|
||||
I16(Int16),
|
||||
I32(Int32),
|
||||
I64(Int64),
|
||||
I128(Int128),
|
||||
|
||||
Array(Vec<Value>),
|
||||
Tuple(Vec<Value>),
|
||||
}
|
||||
|
154
core/src/unstable/blake2s.rs
Normal file
154
core/src/unstable/blake2s.rs
Normal file
@ -0,0 +1,154 @@
|
||||
// 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::{CoreCircuit, Value};
|
||||
|
||||
use leo_typed::{
|
||||
Circuit,
|
||||
CircuitMember,
|
||||
Expression,
|
||||
Function,
|
||||
FunctionInput,
|
||||
Identifier,
|
||||
InputVariable,
|
||||
IntegerType,
|
||||
Span,
|
||||
Statement,
|
||||
Type,
|
||||
};
|
||||
use snarkos_gadgets::algorithms::prf::Blake2sGadget;
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{
|
||||
algorithms::PRFGadget,
|
||||
r1cs::ConstraintSystem,
|
||||
utilities::{uint::UInt8, ToBytesGadget},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Blake2sFunction {}
|
||||
|
||||
impl CoreCircuit for Blake2sFunction {
|
||||
/* Hardcode blake2s circuit ast
|
||||
* circuit Blake2s {
|
||||
* static function hash(seed: [u8; 32], message: [u8; 32]) -> [u8; 32] {
|
||||
* // call `check_eval_gadget` in snarkOS
|
||||
* return check_eval_gadget(seed, message)
|
||||
* }
|
||||
*/
|
||||
fn ast(circuit_name: Identifier, span: Span) -> Circuit {
|
||||
Circuit {
|
||||
circuit_name,
|
||||
members: vec![CircuitMember::CircuitFunction(
|
||||
true, // static function
|
||||
Function {
|
||||
identifier: Identifier {
|
||||
name: "hash".to_owned(),
|
||||
span: span.clone(),
|
||||
},
|
||||
input: vec![
|
||||
InputVariable::FunctionInput(FunctionInput {
|
||||
identifier: Identifier {
|
||||
name: "seed".to_owned(),
|
||||
span: span.clone(),
|
||||
},
|
||||
mutable: false,
|
||||
type_: Type::Array(Box::new(Type::IntegerType(IntegerType::U8)), vec![32usize]),
|
||||
span: span.clone(),
|
||||
}),
|
||||
InputVariable::FunctionInput(FunctionInput {
|
||||
identifier: Identifier {
|
||||
name: "message".to_owned(),
|
||||
span: span.clone(),
|
||||
},
|
||||
mutable: false,
|
||||
type_: Type::Array(Box::new(Type::IntegerType(IntegerType::U8)), vec![32usize]),
|
||||
span: span.clone(),
|
||||
}),
|
||||
],
|
||||
returns: Some(Type::Array(Box::new(Type::IntegerType(IntegerType::U8)), vec![32usize])),
|
||||
statements: vec![Statement::Return(
|
||||
Expression::CoreFunctionCall(
|
||||
"core_blake2s_unstable".to_owned(),
|
||||
vec![
|
||||
Expression::Identifier(Identifier {
|
||||
name: "seed".to_owned(),
|
||||
span: span.clone(),
|
||||
}),
|
||||
Expression::Identifier(Identifier {
|
||||
name: "message".to_owned(),
|
||||
span: span.clone(),
|
||||
}),
|
||||
],
|
||||
span.clone(),
|
||||
),
|
||||
span.clone(),
|
||||
)],
|
||||
span: span.clone(),
|
||||
},
|
||||
)],
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
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 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)]
|
||||
}
|
||||
}
|
||||
|
||||
fn check_array_bytes(value: Value, size: usize) -> Vec<UInt8> {
|
||||
let array_value = match value {
|
||||
Value::Array(array) => array,
|
||||
_ => unimplemented!("expected array value"),
|
||||
};
|
||||
|
||||
if array_value.len() != size {
|
||||
unimplemented!("expected array size of {}", size)
|
||||
}
|
||||
|
||||
let mut array_bytes = vec![];
|
||||
|
||||
for value in array_value {
|
||||
let byte = match value {
|
||||
Value::U8(u8) => u8,
|
||||
_ => unimplemented!("expected u8 byte"),
|
||||
};
|
||||
|
||||
array_bytes.push(byte)
|
||||
}
|
||||
|
||||
array_bytes
|
||||
}
|
@ -14,4 +14,5 @@
|
||||
// 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 unstable;
|
||||
pub mod blake2s;
|
||||
pub use self::blake2s::*;
|
@ -114,7 +114,7 @@ pub enum Expression {
|
||||
// (declared_function_name, function_arguments, span)
|
||||
FunctionCall(Box<Expression>, Vec<Expression>, Span),
|
||||
// (core_function_name, function_arguments, span)
|
||||
CoreFunctionCall(String, Vec<Expression>),
|
||||
CoreFunctionCall(String, Vec<Expression>, Span),
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
@ -150,6 +150,7 @@ impl Expression {
|
||||
Expression::CircuitStaticFunctionAccess(_, _, old_span) => *old_span = new_span.clone(),
|
||||
|
||||
Expression::FunctionCall(_, _, old_span) => *old_span = new_span.clone(),
|
||||
Expression::CoreFunctionCall(_, _, old_span) => *old_span = new_span.clone(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -280,7 +281,7 @@ impl<'ast> fmt::Display for Expression {
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
Expression::CoreFunctionCall(ref function, ref arguments) => {
|
||||
Expression::CoreFunctionCall(ref function, ref arguments, ref _span) => {
|
||||
write!(f, "{}(", function,)?;
|
||||
for (i, param) in arguments.iter().enumerate() {
|
||||
write!(f, "{}", param)?;
|
||||
|
Loading…
Reference in New Issue
Block a user