mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-09-11 05:45:30 +03:00
refactor main function parameters
This commit is contained in:
parent
d3989c36fd
commit
e720409ca3
@ -1,10 +1,5 @@
|
||||
function test(a: u32) {
|
||||
a = 5;
|
||||
}
|
||||
function main(a: private fe) {
|
||||
let b = a + 1fe;
|
||||
|
||||
function main() -> u32 {
|
||||
let a = 1;
|
||||
test(a);
|
||||
|
||||
return a
|
||||
assert_eq(b, 2fe);
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
use leo_compiler::{self, ast};
|
||||
use leo_compiler::errors::CompilerError;
|
||||
use leo_compiler::{self, ast, ParameterValue, Program};
|
||||
|
||||
use snarkos_algorithms::snark::{
|
||||
create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof,
|
||||
@ -18,23 +19,23 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Benchmark<F: Field + PrimeField> {
|
||||
program: Program<F>,
|
||||
parameters: Vec<Option<ParameterValue<F>>>,
|
||||
_engine: PhantomData<F>,
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> Benchmark<F> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
program: Program::new(),
|
||||
parameters: vec![],
|
||||
_engine: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> ConstraintSynthesizer<F> for Benchmark<F> {
|
||||
fn generate_constraints<CS: ConstraintSystem<F>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
) -> Result<(), SynthesisError> {
|
||||
pub fn evaluate_program(&mut self) -> Result<(), CompilerError> {
|
||||
// Read in file as string
|
||||
let unparsed_file = fs::read_to_string("simple.leo").expect("cannot read file");
|
||||
|
||||
@ -45,14 +46,26 @@ impl<F: Field + PrimeField> ConstraintSynthesizer<F> for Benchmark<F> {
|
||||
let syntax_tree = ast::File::from_pest(&mut file).expect("infallible");
|
||||
// println!("{:#?}", syntax_tree);
|
||||
|
||||
let program = leo_compiler::Program::<'_, F>::from(syntax_tree);
|
||||
println!(" compiled: {:#?}", program);
|
||||
// Build a leo program from the syntax tree
|
||||
self.program = Program::<F>::from(syntax_tree, "simple".into());
|
||||
self.parameters = vec![None; self.program.num_parameters];
|
||||
|
||||
let program = program.name("simple".into());
|
||||
println!(
|
||||
"Result: {}",
|
||||
leo_compiler::ResolvedProgram::generate_constraints(cs, program)
|
||||
);
|
||||
println!(" compiled: {:#?}\n", self.program);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> ConstraintSynthesizer<F> for Benchmark<F> {
|
||||
fn generate_constraints<CS: ConstraintSystem<F>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
) -> Result<(), SynthesisError> {
|
||||
let _res =
|
||||
leo_compiler::ResolvedProgram::generate_constraints(cs, self.program, self.parameters);
|
||||
println!(" Result: {}", _res);
|
||||
|
||||
// Write results to file or something
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -67,27 +80,33 @@ fn main() {
|
||||
|
||||
let start = Instant::now();
|
||||
|
||||
let params = {
|
||||
let circuit = Benchmark::<Fr>::new();
|
||||
generate_random_parameters::<Bls12_377, _, _>(circuit, rng).unwrap()
|
||||
};
|
||||
// Load and compile program
|
||||
let mut program = Benchmark::<Fr>::new();
|
||||
program.evaluate_program().unwrap();
|
||||
|
||||
// Generate proof parameters
|
||||
let params = { generate_random_parameters::<Bls12_377, _, _>(program.clone(), rng).unwrap() };
|
||||
|
||||
let prepared_verifying_key = prepare_verifying_key::<Bls12_377>(¶ms.vk);
|
||||
|
||||
setup += start.elapsed();
|
||||
|
||||
let start = Instant::now();
|
||||
let proof = {
|
||||
let c = Benchmark::new();
|
||||
create_random_proof(c, ¶ms, rng).unwrap()
|
||||
};
|
||||
|
||||
// Set main function arguments in compiled program
|
||||
let argument = Some(ParameterValue::Field(Fr::one()));
|
||||
program.parameters = vec![argument];
|
||||
|
||||
// Generate proof
|
||||
let proof = create_random_proof(program, ¶ms, rng).unwrap();
|
||||
|
||||
proving += start.elapsed();
|
||||
|
||||
// let _inputs: Vec<_> = [1u32; 1].to_vec();
|
||||
|
||||
let start = Instant::now();
|
||||
|
||||
// let public_input = Fr::one();
|
||||
|
||||
// Verify proof
|
||||
let is_success = verify_proof(&prepared_verifying_key, &proof, &[]).unwrap();
|
||||
|
||||
verifying += start.elapsed();
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::errors::CompilerError;
|
||||
use crate::{ast, Program, ResolvedProgram, ResolvedValue};
|
||||
use crate::{ast, ParameterValue, Program, ResolvedProgram, ResolvedValue};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use snarkos_models::{
|
||||
@ -15,6 +15,8 @@ use std::{fs, marker::PhantomData, path::PathBuf};
|
||||
pub struct Compiler<F: Field + PrimeField> {
|
||||
package_name: String,
|
||||
main_file_path: PathBuf,
|
||||
program: Program<F>,
|
||||
parameters: Vec<Option<ParameterValue<F>>>,
|
||||
output: Option<ResolvedValue<F>>,
|
||||
_engine: PhantomData<F>,
|
||||
}
|
||||
@ -24,6 +26,8 @@ impl<F: Field + PrimeField> Compiler<F> {
|
||||
Self {
|
||||
package_name,
|
||||
main_file_path,
|
||||
program: Program::new(),
|
||||
parameters: vec![],
|
||||
output: None,
|
||||
_engine: PhantomData,
|
||||
}
|
||||
@ -56,10 +60,7 @@ impl<F: Field + PrimeField> Compiler<F> {
|
||||
// Ok(syntax_tree)
|
||||
// }
|
||||
|
||||
pub fn evaluate_program<CS: ConstraintSystem<F>>(
|
||||
&self,
|
||||
cs: &mut CS,
|
||||
) -> Result<ResolvedValue<F>, CompilerError> {
|
||||
pub fn evaluate_program<CS: ConstraintSystem<F>>(&mut self) -> Result<(), CompilerError> {
|
||||
// Read in the main file as string
|
||||
let unparsed_file = fs::read_to_string(&self.main_file_path)
|
||||
.map_err(|_| CompilerError::FileReadError(self.main_file_path.clone()))?;
|
||||
@ -74,10 +75,13 @@ impl<F: Field + PrimeField> Compiler<F> {
|
||||
|
||||
// Build program from abstract syntax tree
|
||||
let package_name = self.package_name.clone();
|
||||
let program = Program::<'_, F>::from(syntax_tree).name(package_name);
|
||||
log::debug!("Compilation complete\n{:#?}", program);
|
||||
|
||||
Ok(ResolvedProgram::generate_constraints(cs, program))
|
||||
self.program = Program::<F>::from(syntax_tree, package_name);
|
||||
self.parameters = vec![None; self.program.num_parameters];
|
||||
|
||||
log::debug!("Compilation complete\n{:#?}", self.program);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,7 +90,10 @@ impl<F: Field + PrimeField> ConstraintSynthesizer<F> for Compiler<F> {
|
||||
self,
|
||||
cs: &mut CS,
|
||||
) -> Result<(), SynthesisError> {
|
||||
self.evaluate_program(cs).expect("error compiling program");
|
||||
let _res = ResolvedProgram::generate_constraints(cs, self.program, self.parameters);
|
||||
|
||||
// Write results to file or something
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
//! Methods to enforce constraints on booleans in a resolved aleo program.
|
||||
|
||||
use crate::constraints::{ResolvedProgram, ResolvedValue};
|
||||
use crate::{new_variable_from_variable, Parameter, Variable};
|
||||
use crate::{new_variable_from_variable, ParameterModel, ParameterValue, Variable};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
use snarkos_models::gadgets::{
|
||||
r1cs::ConstraintSystem,
|
||||
@ -14,31 +15,30 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
scope: String,
|
||||
index: usize,
|
||||
parameter: Parameter<F>,
|
||||
parameter_model: ParameterModel<F>,
|
||||
parameter_value: Option<ParameterValue<F>>,
|
||||
) -> Variable<F> {
|
||||
// Get command line argument for each parameter in program
|
||||
let argument = std::env::args()
|
||||
.nth(index)
|
||||
.expect(&format!(
|
||||
"expected command line argument at index {}",
|
||||
index
|
||||
))
|
||||
.parse::<bool>()
|
||||
.expect(&format!(
|
||||
"expected main function parameter {} at index {}",
|
||||
parameter, index
|
||||
));
|
||||
// Check that the parameter value is the correct type
|
||||
let bool_value = parameter_value.map(|parameter| match parameter {
|
||||
ParameterValue::Boolean(b) => b,
|
||||
value => unimplemented!("expected boolean parameter, got {}", value),
|
||||
});
|
||||
|
||||
// Check visibility of parameter
|
||||
let name = parameter.variable.name.clone();
|
||||
let number = if parameter.private {
|
||||
Boolean::alloc(cs.ns(|| name), || Ok(argument)).unwrap()
|
||||
let name = parameter_model.variable.name.clone();
|
||||
let number = if parameter_model.private {
|
||||
Boolean::alloc(cs.ns(|| name), || {
|
||||
bool_value.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.unwrap()
|
||||
} else {
|
||||
Boolean::alloc_input(cs.ns(|| name), || Ok(argument)).unwrap()
|
||||
Boolean::alloc_input(cs.ns(|| name), || {
|
||||
bool_value.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let parameter_variable = new_variable_from_variable(scope, ¶meter.variable);
|
||||
let parameter_variable = new_variable_from_variable(scope, ¶meter_model.variable);
|
||||
|
||||
// store each argument as variable in resolved program
|
||||
self.store_variable(parameter_variable.clone(), ResolvedValue::Boolean(number));
|
||||
@ -50,29 +50,16 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
&mut self,
|
||||
_cs: &mut CS,
|
||||
_scope: String,
|
||||
_index: usize,
|
||||
_parameter: Parameter<F>,
|
||||
_parameter_model: ParameterModel<F>,
|
||||
_parameter_value: Option<ParameterValue<F>>,
|
||||
) -> Variable<F> {
|
||||
unimplemented!("Cannot enforce boolean array as parameter")
|
||||
// // Get command line argument for each parameter in program
|
||||
// let argument_array = std::env::args()
|
||||
// .nth(index)
|
||||
// .expect(&format!(
|
||||
// "expected command line argument at index {}",
|
||||
// index
|
||||
// ))
|
||||
// .parse::<Vec<bool>>()
|
||||
// .expect(&format!(
|
||||
// "expected main function parameter {} at index {}",
|
||||
// parameter, index
|
||||
// ));
|
||||
//
|
||||
// // Check visibility of parameter
|
||||
// let mut array_value = vec![];
|
||||
// let name = parameter.variable.name.clone();
|
||||
// for argument in argument_array {
|
||||
// let number = if parameter.private {
|
||||
// Boolean::alloc(cs.ns(|| name), || Ok(argument)).unwrap()
|
||||
// Boolean::alloc(cs.ns(|| name), ||bool_value.ok_or(SynthesisError::AssignmentMissing).unwrap()
|
||||
// } else {
|
||||
// Boolean::alloc_input(cs.ns(|| name), || Ok(argument)).unwrap()
|
||||
// };
|
||||
|
@ -7,13 +7,14 @@ use crate::{
|
||||
ResolvedValue,
|
||||
},
|
||||
types::{Expression, Function, Program, Type},
|
||||
Import,
|
||||
Import, ParameterValue,
|
||||
};
|
||||
|
||||
use from_pest::FromPest;
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
use snarkos_models::gadgets::r1cs::ConstraintSystem;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
fn enforce_argument(
|
||||
@ -87,13 +88,13 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function_name.clone(),
|
||||
argument,
|
||||
) {
|
||||
ResolvedValue::FieldElement(field) => {
|
||||
ResolvedValue::FieldElement(fe) => {
|
||||
// Store argument as variable with {function_name}_{parameter name}
|
||||
let variable_name = new_scope_from_variable(
|
||||
function_name.clone(),
|
||||
¶meter.variable,
|
||||
);
|
||||
self.store(variable_name, ResolvedValue::FieldElement(field));
|
||||
self.store(variable_name, ResolvedValue::FieldElement(fe));
|
||||
}
|
||||
argument => unimplemented!("expected field argument got {}", argument),
|
||||
}
|
||||
@ -148,49 +149,58 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
cs: &mut CS,
|
||||
scope: String,
|
||||
function: Function<F>,
|
||||
parameters: Vec<Option<ParameterValue<F>>>,
|
||||
) -> ResolvedValue<F> {
|
||||
let function_name = new_scope(scope.clone(), function.get_name());
|
||||
let mut arguments = vec![];
|
||||
|
||||
// todo: check parameters length for each
|
||||
|
||||
// Iterate over main function parameters
|
||||
function
|
||||
.parameters
|
||||
.clone()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.for_each(|(i, parameter)| {
|
||||
.zip(parameters.into_iter())
|
||||
.for_each(|(parameter_model, parameter_value)| {
|
||||
// append each variable to arguments vector
|
||||
arguments.push(Expression::Variable(match parameter.ty {
|
||||
Type::U32 => {
|
||||
self.u32_from_parameter(cs, function_name.clone(), i + 1, parameter)
|
||||
}
|
||||
arguments.push(Expression::Variable(match parameter_model.ty {
|
||||
Type::U32 => self.u32_from_parameter(
|
||||
cs,
|
||||
function_name.clone(),
|
||||
parameter_model,
|
||||
parameter_value,
|
||||
),
|
||||
Type::FieldElement => self.field_element_from_parameter(
|
||||
cs,
|
||||
function_name.clone(),
|
||||
i + 1,
|
||||
parameter,
|
||||
parameter_model,
|
||||
parameter_value,
|
||||
),
|
||||
Type::Boolean => self.bool_from_parameter(
|
||||
cs,
|
||||
function_name.clone(),
|
||||
parameter_model,
|
||||
parameter_value,
|
||||
),
|
||||
Type::Boolean => {
|
||||
self.bool_from_parameter(cs, function_name.clone(), i + 1, parameter)
|
||||
}
|
||||
Type::Array(ref ty, _length) => match *ty.clone() {
|
||||
Type::U32 => self.u32_array_from_parameter(
|
||||
cs,
|
||||
function_name.clone(),
|
||||
i + 1,
|
||||
parameter,
|
||||
parameter_model,
|
||||
parameter_value,
|
||||
),
|
||||
Type::FieldElement => self.field_element_array_from_parameter(
|
||||
cs,
|
||||
function_name.clone(),
|
||||
i + 1,
|
||||
parameter,
|
||||
parameter_model,
|
||||
parameter_value,
|
||||
),
|
||||
Type::Boolean => self.boolean_array_from_parameter(
|
||||
cs,
|
||||
function_name.clone(),
|
||||
i + 1,
|
||||
parameter,
|
||||
parameter_model,
|
||||
parameter_value,
|
||||
),
|
||||
ty => unimplemented!("parameter type not implemented {}", ty),
|
||||
},
|
||||
@ -203,16 +213,19 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|
||||
fn enforce_import(&mut self, cs: &mut CS, scope: String, import: Import<F>) {
|
||||
// Resolve program file path
|
||||
let unparsed_file = fs::read_to_string(import.get_file())
|
||||
.expect(&format!("cannot parse import {}", import.get_file()));
|
||||
let mut file = ast::parse(&unparsed_file)
|
||||
.expect(&format!("cannot parse import {}", import.get_file()));
|
||||
let unparsed_file = fs::read_to_string(Path::new(&import.path_string_full())).expect(
|
||||
&format!("cannot parse import {}", import.path_string_full()),
|
||||
);
|
||||
let mut file = ast::parse(&unparsed_file).expect(&format!(
|
||||
"cannot parse import {}",
|
||||
import.path_string_full()
|
||||
));
|
||||
|
||||
// generate ast from file
|
||||
let syntax_tree = ast::File::from_pest(&mut file).expect("infallible");
|
||||
|
||||
// generate aleo program from file
|
||||
let mut program = Program::from(syntax_tree);
|
||||
let mut program = Program::from(syntax_tree, import.path_string.clone());
|
||||
|
||||
// Use same namespace as calling function for imported symbols
|
||||
program = program.name(scope);
|
||||
@ -316,7 +329,11 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn generate_constraints(cs: &mut CS, program: Program<F>) -> ResolvedValue<F> {
|
||||
pub fn generate_constraints(
|
||||
cs: &mut CS,
|
||||
program: Program<F>,
|
||||
parameters: Vec<Option<ParameterValue<F>>>,
|
||||
) -> ResolvedValue<F> {
|
||||
let mut resolved_program = ResolvedProgram::new();
|
||||
let program_name = program.get_name();
|
||||
let main_function_name = new_scope(program_name.clone(), "main".into());
|
||||
@ -329,7 +346,8 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|
||||
match main.clone() {
|
||||
ResolvedValue::Function(function) => {
|
||||
let result = resolved_program.enforce_main_function(cs, program_name, function);
|
||||
let result =
|
||||
resolved_program.enforce_main_function(cs, program_name, function, parameters);
|
||||
log::debug!("{}", result);
|
||||
result
|
||||
}
|
||||
|
@ -40,13 +40,13 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::U32(num1), ResolvedValue::U32(num2)) => {
|
||||
Self::enforce_u32_add(cs, num1, num2)
|
||||
(ResolvedValue::U32(num_1), ResolvedValue::U32(num_2)) => {
|
||||
Self::enforce_u32_add(cs, num_1, num_2)
|
||||
}
|
||||
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||
self.enforce_field_add(fe1, fe2)
|
||||
(ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
self.enforce_field_add(cs, fe_1, fe_2)
|
||||
}
|
||||
(val1, val2) => unimplemented!("cannot add {} + {}", val1, val2),
|
||||
(val_1, val_2) => unimplemented!("cannot add {} + {}", val_1, val_2),
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,13 +57,13 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::U32(num1), ResolvedValue::U32(num2)) => {
|
||||
Self::enforce_u32_sub(cs, num1, num2)
|
||||
(ResolvedValue::U32(num_1), ResolvedValue::U32(num_2)) => {
|
||||
Self::enforce_u32_sub(cs, num_1, num_2)
|
||||
}
|
||||
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||
self.enforce_field_sub(fe1, fe2)
|
||||
(ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
self.enforce_field_sub(cs, fe_1, fe_2)
|
||||
}
|
||||
(val1, val2) => unimplemented!("cannot subtract {} - {}", val1, val2),
|
||||
(val_1, val_2) => unimplemented!("cannot subtract {} - {}", val_1, val_2),
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,13 +74,13 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::U32(num1), ResolvedValue::U32(num2)) => {
|
||||
Self::enforce_u32_mul(cs, num1, num2)
|
||||
(ResolvedValue::U32(num_1), ResolvedValue::U32(num_2)) => {
|
||||
Self::enforce_u32_mul(cs, num_1, num_2)
|
||||
}
|
||||
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||
self.enforce_field_mul(fe1, fe2)
|
||||
(ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
self.enforce_field_mul(cs, fe_1, fe_2)
|
||||
}
|
||||
(val1, val2) => unimplemented!("cannot multiply {} * {}", val1, val2),
|
||||
(val_1, val_2) => unimplemented!("cannot multiply {} * {}", val_1, val_2),
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,13 +91,13 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::U32(num1), ResolvedValue::U32(num2)) => {
|
||||
Self::enforce_u32_div(cs, num1, num2)
|
||||
(ResolvedValue::U32(num_1), ResolvedValue::U32(num_2)) => {
|
||||
Self::enforce_u32_div(cs, num_1, num_2)
|
||||
}
|
||||
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||
self.enforce_field_div(fe1, fe2)
|
||||
(ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
self.enforce_field_div(cs, fe_1, fe_2)
|
||||
}
|
||||
(val1, val2) => unimplemented!("cannot divide {} / {}", val1, val2),
|
||||
(val_1, val_2) => unimplemented!("cannot divide {} / {}", val_1, val_2),
|
||||
}
|
||||
}
|
||||
fn enforce_pow_expression(
|
||||
@ -107,16 +107,16 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::U32(num1), ResolvedValue::U32(num2)) => {
|
||||
Self::enforce_u32_pow(cs, num1, num2)
|
||||
(ResolvedValue::U32(num_1), ResolvedValue::U32(num_2)) => {
|
||||
Self::enforce_u32_pow(cs, num_1, num_2)
|
||||
}
|
||||
(ResolvedValue::FieldElement(fe1), ResolvedValue::U32(num2)) => {
|
||||
self.enforce_field_pow(fe1, num2)
|
||||
(ResolvedValue::FieldElement(fe_1), ResolvedValue::U32(num_2)) => {
|
||||
self.enforce_field_pow(cs, fe_1, num_2)
|
||||
}
|
||||
(_, ResolvedValue::FieldElement(num2)) => {
|
||||
unimplemented!("exponent power must be an integer, got field {}", num2)
|
||||
(_, ResolvedValue::FieldElement(num_2)) => {
|
||||
unimplemented!("exponent power must be an integer, got field {}", num_2)
|
||||
}
|
||||
(val1, val2) => unimplemented!("cannot enforce exponentiation {} * {}", val1, val2),
|
||||
(val_1, val_2) => unimplemented!("cannot enforce exponentiation {} * {}", val_1, val_2),
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,14 +127,14 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::Boolean(bool1), ResolvedValue::Boolean(bool2)) => {
|
||||
Self::boolean_eq(bool1, bool2)
|
||||
(ResolvedValue::Boolean(bool_1), ResolvedValue::Boolean(bool_2)) => {
|
||||
Self::boolean_eq(bool_1, bool_2)
|
||||
}
|
||||
(ResolvedValue::U32(num1), ResolvedValue::U32(num2)) => Self::u32_eq(num1, num2),
|
||||
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||
Self::field_eq(fe1, fe2)
|
||||
}
|
||||
(val1, val2) => unimplemented!("cannot evaluate {} == {}", val1, val2),
|
||||
(ResolvedValue::U32(num_1), ResolvedValue::U32(num_2)) => Self::u32_eq(num_1, num_2),
|
||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
// Self::field_eq(fe_1, fe_2)
|
||||
// }
|
||||
(val_1, val_2) => unimplemented!("cannot evaluate {} == {}", val_1, val_2),
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,13 +144,13 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||
Self::field_geq(fe1, fe2)
|
||||
}
|
||||
(val1, val2) => unimplemented!(
|
||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
// Self::field_geq(fe_1, fe_2)
|
||||
// }
|
||||
(val_1, val_2) => unimplemented!(
|
||||
"cannot evaluate {} >= {}, values must be fields",
|
||||
val1,
|
||||
val2
|
||||
val_1,
|
||||
val_2
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -161,12 +161,14 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||
Self::field_gt(fe1, fe2)
|
||||
}
|
||||
(val1, val2) => {
|
||||
unimplemented!("cannot evaluate {} > {}, values must be fields", val1, val2)
|
||||
}
|
||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
// Self::field_gt(fe_1, fe_2)
|
||||
// }
|
||||
(val_1, val_2) => unimplemented!(
|
||||
"cannot evaluate {} > {}, values must be fields",
|
||||
val_1,
|
||||
val_2
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,13 +178,13 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||
Self::field_leq(fe1, fe2)
|
||||
}
|
||||
(val1, val2) => unimplemented!(
|
||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
// Self::field_leq(fe_1, fe_2)
|
||||
// }
|
||||
(val_1, val_2) => unimplemented!(
|
||||
"cannot evaluate {} <= {}, values must be fields",
|
||||
val1,
|
||||
val2
|
||||
val_1,
|
||||
val_2
|
||||
),
|
||||
}
|
||||
}
|
||||
@ -193,12 +195,14 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||
Self::field_lt(fe1, fe2)
|
||||
}
|
||||
(val1, val2) => {
|
||||
unimplemented!("cannot evaluate {} < {}, values must be fields", val1, val2)
|
||||
}
|
||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
// Self::field_lt(fe_1, fe_2)
|
||||
// }
|
||||
(val_1, val_2) => unimplemented!(
|
||||
"cannot evaluate {} < {}, values must be fields",
|
||||
val_1,
|
||||
val_2
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,7 +408,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|
||||
// Values
|
||||
Expression::Integer(integer) => Self::get_integer_constant(integer),
|
||||
Expression::FieldElement(fe) => ResolvedValue::FieldElement(fe),
|
||||
Expression::FieldElement(fe) => Self::get_field_element_constant(fe),
|
||||
Expression::Boolean(bool) => Self::get_boolean_constant(bool),
|
||||
|
||||
// Binary operations
|
||||
|
@ -1,46 +1,51 @@
|
||||
//! Methods to enforce constraints on field elements in a resolved aleo program.
|
||||
|
||||
use crate::constraints::{ResolvedProgram, ResolvedValue};
|
||||
use crate::{new_variable_from_variable, Parameter, Variable};
|
||||
use crate::{new_variable_from_variable, FieldElement, ParameterModel, ParameterValue, Variable};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
use snarkos_models::gadgets::r1cs::LinearCombination;
|
||||
use snarkos_models::gadgets::utilities::uint32::UInt32;
|
||||
use snarkos_models::gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean};
|
||||
// use std::ops::{Add, Div, Mul, Neg, Sub};
|
||||
use snarkos_models::gadgets::{
|
||||
r1cs::{ConstraintSystem, LinearCombination, Variable as R1CSVariable},
|
||||
utilities::uint32::UInt32,
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
pub(crate) fn field_element_from_parameter(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
scope: String,
|
||||
index: usize,
|
||||
parameter: Parameter<F>,
|
||||
parameter_model: ParameterModel<F>,
|
||||
parameter_value: Option<ParameterValue<F>>,
|
||||
) -> Variable<F> {
|
||||
// Get command line argument for each parameter in program
|
||||
let argument: F = std::env::args()
|
||||
.nth(index)
|
||||
.expect(&format!(
|
||||
"expected command line argument at index {}",
|
||||
index
|
||||
))
|
||||
.parse::<F>()
|
||||
.unwrap_or_default();
|
||||
// Check that the parameter value is the correct type
|
||||
let field_option = parameter_value.map(|parameter| match parameter {
|
||||
ParameterValue::Field(f) => f,
|
||||
value => unimplemented!("expected field parameter, got {}", value),
|
||||
});
|
||||
|
||||
// Check visibility of parameter
|
||||
let name = parameter.variable.name.clone();
|
||||
if parameter.private {
|
||||
cs.alloc(|| name, || Ok(argument.clone())).unwrap();
|
||||
let name = parameter_model.variable.name.clone();
|
||||
let field_value = if parameter_model.private {
|
||||
cs.alloc(
|
||||
|| name,
|
||||
|| field_option.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap()
|
||||
} else {
|
||||
cs.alloc_input(|| name, || Ok(argument.clone())).unwrap();
|
||||
}
|
||||
cs.alloc_input(
|
||||
|| name,
|
||||
|| field_option.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let parameter_variable = new_variable_from_variable(scope, ¶meter.variable);
|
||||
let parameter_variable = new_variable_from_variable(scope, ¶meter_model.variable);
|
||||
|
||||
// store each argument as variable in resolved program
|
||||
// Store parameter as variable in resolved program
|
||||
self.store_variable(
|
||||
parameter_variable.clone(),
|
||||
ResolvedValue::FieldElement(argument),
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(field_option, field_value)),
|
||||
);
|
||||
|
||||
parameter_variable
|
||||
@ -50,24 +55,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
&mut self,
|
||||
_cs: &mut CS,
|
||||
_scope: String,
|
||||
_index: usize,
|
||||
_parameter: Parameter<F>,
|
||||
_parameter_model: ParameterModel<F>,
|
||||
_parameter_value: Option<ParameterValue<F>>,
|
||||
) -> Variable<F> {
|
||||
unimplemented!("Cannot enforce field element array as parameter")
|
||||
|
||||
// // Get command line argument for each parameter in program
|
||||
// let argument_array = std::env::args()
|
||||
// .nth(index)
|
||||
// .expect(&format!(
|
||||
// "expected command line argument at index {}",
|
||||
// index
|
||||
// ))
|
||||
// .parse::<Vec<F>>()
|
||||
// .expect(&format!(
|
||||
// "expected main function parameter {} at index {}",
|
||||
// parameter, index
|
||||
// ));
|
||||
//
|
||||
// // Check visibility of parameter
|
||||
// let mut array_value = vec![];
|
||||
// let name = parameter.variable.name.clone();
|
||||
@ -88,53 +79,450 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
// parameter_variable
|
||||
}
|
||||
|
||||
pub(crate) fn field_eq(fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
ResolvedValue::Boolean(Boolean::Constant(fe1.eq(&fe2)))
|
||||
pub(crate) fn get_field_element_constant(fe: F) -> ResolvedValue<F> {
|
||||
ResolvedValue::FieldElement(FieldElement::Constant(fe))
|
||||
}
|
||||
|
||||
pub(crate) fn field_geq(fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
ResolvedValue::Boolean(Boolean::Constant(fe1.ge(&fe2)))
|
||||
}
|
||||
// pub(crate) fn field_eq(fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
// ResolvedValue::Boolean(Boolean::Constant(fe1.eq(&fe2)))
|
||||
// }
|
||||
//
|
||||
// pub(crate) fn field_geq(fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
// ResolvedValue::Boolean(Boolean::Constant(fe1.ge(&fe2)))
|
||||
// }
|
||||
//
|
||||
// pub(crate) fn field_gt(fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
// ResolvedValue::Boolean(Boolean::Constant(fe1.gt(&fe2)))
|
||||
// }
|
||||
//
|
||||
// pub(crate) fn field_leq(fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
// ResolvedValue::Boolean(Boolean::Constant(fe1.le(&fe2)))
|
||||
// }
|
||||
//
|
||||
// pub(crate) fn field_lt(fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
// ResolvedValue::Boolean(Boolean::Constant(fe1.lt(&fe2)))
|
||||
// }
|
||||
|
||||
pub(crate) fn field_gt(fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
ResolvedValue::Boolean(Boolean::Constant(fe1.gt(&fe2)))
|
||||
}
|
||||
|
||||
pub(crate) fn field_leq(fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
ResolvedValue::Boolean(Boolean::Constant(fe1.le(&fe2)))
|
||||
}
|
||||
|
||||
pub(crate) fn field_lt(fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
ResolvedValue::Boolean(Boolean::Constant(fe1.lt(&fe2)))
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_field_eq(&mut self, cs: &mut CS, fe1: F, fe2: F) {
|
||||
pub(crate) fn enforce_field_eq(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
fe_1: FieldElement<F>,
|
||||
fe_2: FieldElement<F>,
|
||||
) {
|
||||
let mut lc = LinearCombination::zero();
|
||||
|
||||
// add (fe1 * 1) and subtract (fe2 * 1) from the linear combination
|
||||
lc = lc + (fe1, CS::one()) - (fe2, CS::one());
|
||||
match (fe_1, fe_2) {
|
||||
(FieldElement::Constant(fe_1_constant), FieldElement::Constant(fe_2_constant)) => {
|
||||
// lc = lc + (fe_1_constant * 1) - (fe_2_constant * 1)
|
||||
// lc = lc + fe_1 - fe_2
|
||||
lc = lc + (fe_1_constant, CS::one()) - (fe_2_constant, CS::one());
|
||||
}
|
||||
// else, return an allocated result
|
||||
(
|
||||
FieldElement::Allocated(_fe_1_value, fe_1_variable),
|
||||
FieldElement::Constant(fe_2_constant),
|
||||
) => {
|
||||
// lc = lc + fe_1 - (fe_2_constant * 1)
|
||||
// lc = lc + fe_1 - fe_2
|
||||
lc = lc + fe_1_variable - (fe_2_constant, CS::one())
|
||||
}
|
||||
(
|
||||
FieldElement::Constant(fe_1_constant),
|
||||
FieldElement::Allocated(_fe_2_value, fe_2_variable),
|
||||
) => {
|
||||
// lc = lc + (fe_1_constant * 1) - fe_2
|
||||
// lc = lc + fe_1 - fe_2
|
||||
lc = lc + (fe_1_constant, CS::one()) - fe_2_variable
|
||||
}
|
||||
(
|
||||
FieldElement::Allocated(_fe_1_value, fe_1_variable),
|
||||
FieldElement::Allocated(_fe_2_value, fe_2_variable),
|
||||
) => {
|
||||
// lc = lc + fe_1 - fe_2
|
||||
lc = lc + fe_1_variable - fe_2_variable
|
||||
}
|
||||
}
|
||||
|
||||
// enforce that the linear combination is zero
|
||||
cs.enforce(|| "field equality", |lc| lc, |lc| lc, |_| lc);
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_field_add(&mut self, fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
ResolvedValue::FieldElement(fe1.add(&fe2))
|
||||
pub(crate) fn enforce_field_add(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
fe_1: FieldElement<F>,
|
||||
fe_2: FieldElement<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
match (fe_1, fe_2) {
|
||||
// if both constants, then return a constant result
|
||||
(FieldElement::Constant(fe_1_constant), FieldElement::Constant(fe_2_constant)) => {
|
||||
ResolvedValue::FieldElement(FieldElement::Constant(
|
||||
fe_1_constant.add(&fe_2_constant),
|
||||
))
|
||||
}
|
||||
// else, return an allocated result
|
||||
(
|
||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
||||
FieldElement::Constant(fe_2_constant),
|
||||
) => {
|
||||
let sum_value: Option<F> = fe_1_value.map(|v| v.add(&fe_2_constant));
|
||||
let sum_variable: R1CSVariable = cs
|
||||
.alloc(
|
||||
|| "field addition",
|
||||
|| sum_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
cs.enforce(
|
||||
|| "sum = 1 * (fe_1 + fe2)",
|
||||
|lc| lc + CS::one(),
|
||||
|lc| lc + fe_1_variable + (fe_2_constant, CS::one()),
|
||||
|lc| lc + sum_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(sum_value, sum_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Constant(fe_1_constant),
|
||||
FieldElement::Allocated(fe_2_value, fe_2_variable),
|
||||
) => {
|
||||
let sum_value: Option<F> = fe_2_value.map(|v| fe_1_constant.add(&v));
|
||||
let sum_variable: R1CSVariable = cs
|
||||
.alloc(
|
||||
|| "field addition",
|
||||
|| sum_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
cs.enforce(
|
||||
|| "sum = 1 * (fe_1 + fe_2)",
|
||||
|lc| lc + CS::one(),
|
||||
|lc| lc + (fe_1_constant, CS::one()) + fe_2_variable,
|
||||
|lc| lc + sum_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(sum_value, sum_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
||||
FieldElement::Allocated(fe_2_value, fe_2_variable),
|
||||
) => {
|
||||
let sum_value: Option<F> = match (fe_1_value, fe_2_value) {
|
||||
(Some(fe_1_value), Some(fe_2_value)) => Some(fe_1_value.add(&fe_2_value)),
|
||||
(_, _) => None,
|
||||
};
|
||||
let sum_variable: R1CSVariable = cs
|
||||
.alloc(
|
||||
|| "field addition",
|
||||
|| sum_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
cs.enforce(
|
||||
|| "sum = 1 * (fe_1 + fe_2)",
|
||||
|lc| lc + CS::one(),
|
||||
|lc| lc + fe_1_variable + fe_2_variable,
|
||||
|lc| lc + sum_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(sum_value, sum_variable))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_field_sub(&mut self, fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
ResolvedValue::FieldElement(fe1.sub(&fe2))
|
||||
pub(crate) fn enforce_field_sub(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
fe_1: FieldElement<F>,
|
||||
fe_2: FieldElement<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
match (fe_1, fe_2) {
|
||||
// if both constants, then return a constant result
|
||||
(FieldElement::Constant(fe_1_constant), FieldElement::Constant(fe_2_constant)) => {
|
||||
ResolvedValue::FieldElement(FieldElement::Constant(
|
||||
fe_1_constant.sub(&fe_2_constant),
|
||||
))
|
||||
}
|
||||
// else, return an allocated result
|
||||
(
|
||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
||||
FieldElement::Constant(fe_2_constant),
|
||||
) => {
|
||||
let sub_value: Option<F> = fe_1_value.map(|v| v.sub(&fe_2_constant));
|
||||
let sub_variable: R1CSVariable = cs
|
||||
.alloc(
|
||||
|| "field subtraction",
|
||||
|| sub_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
cs.enforce(
|
||||
|| "sub = 1 * (fe_1 - fe2)",
|
||||
|lc| lc + CS::one(),
|
||||
|lc| lc + fe_1_variable - (fe_2_constant, CS::one()),
|
||||
|lc| lc + sub_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(sub_value, sub_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Constant(fe_1_constant),
|
||||
FieldElement::Allocated(fe_2_value, fe_2_variable),
|
||||
) => {
|
||||
let sub_value: Option<F> = fe_2_value.map(|v| fe_1_constant.sub(&v));
|
||||
let sub_variable: R1CSVariable = cs
|
||||
.alloc(
|
||||
|| "field subtraction",
|
||||
|| sub_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
cs.enforce(
|
||||
|| "sub = 1 * (fe_1 - fe_2)",
|
||||
|lc| lc + CS::one(),
|
||||
|lc| lc + (fe_1_constant, CS::one()) - fe_2_variable,
|
||||
|lc| lc + sub_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(sub_value, sub_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
||||
FieldElement::Allocated(fe_2_value, fe_2_variable),
|
||||
) => {
|
||||
let sub_value: Option<F> = match (fe_1_value, fe_2_value) {
|
||||
(Some(fe_1_value), Some(fe_2_value)) => Some(fe_1_value.sub(&fe_2_value)),
|
||||
(_, _) => None,
|
||||
};
|
||||
let sub_variable: R1CSVariable = cs
|
||||
.alloc(
|
||||
|| "field subtraction",
|
||||
|| sub_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
cs.enforce(
|
||||
|| "sub = 1 * (fe_1 - fe_2)",
|
||||
|lc| lc + CS::one(),
|
||||
|lc| lc + fe_1_variable - fe_2_variable,
|
||||
|lc| lc + sub_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(sub_value, sub_variable))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_field_mul(&mut self, fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
ResolvedValue::FieldElement(fe1.mul(&fe2))
|
||||
pub(crate) fn enforce_field_mul(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
fe_1: FieldElement<F>,
|
||||
fe_2: FieldElement<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
match (fe_1, fe_2) {
|
||||
// if both constants, then return a constant result
|
||||
(FieldElement::Constant(fe_1_constant), FieldElement::Constant(fe_2_constant)) => {
|
||||
ResolvedValue::FieldElement(FieldElement::Constant(
|
||||
fe_1_constant.mul(&fe_2_constant),
|
||||
))
|
||||
}
|
||||
// else, return an allocated result
|
||||
(
|
||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
||||
FieldElement::Constant(fe_2_constant),
|
||||
) => {
|
||||
let mul_value: Option<F> = fe_1_value.map(|v| v.mul(&fe_2_constant));
|
||||
let mul_variable: R1CSVariable = cs
|
||||
.alloc(
|
||||
|| "field multiplication",
|
||||
|| mul_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
cs.enforce(
|
||||
|| "mul = fe_1 * fe_2",
|
||||
|lc| lc + fe_1_variable,
|
||||
|lc| lc + (fe_2_constant, CS::one()),
|
||||
|lc| lc + mul_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(mul_value, mul_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Constant(fe_1_constant),
|
||||
FieldElement::Allocated(fe_2_value, fe_2_variable),
|
||||
) => {
|
||||
let mul_value: Option<F> = fe_2_value.map(|v| fe_1_constant.mul(&v));
|
||||
let mul_variable: R1CSVariable = cs
|
||||
.alloc(
|
||||
|| "field multiplication",
|
||||
|| mul_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
cs.enforce(
|
||||
|| "mul = fe_1 * fe_2",
|
||||
|lc| lc + (fe_1_constant, CS::one()),
|
||||
|lc| lc + fe_2_variable,
|
||||
|lc| lc + mul_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(mul_value, mul_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
||||
FieldElement::Allocated(fe_2_value, fe_2_variable),
|
||||
) => {
|
||||
let mul_value: Option<F> = match (fe_1_value, fe_2_value) {
|
||||
(Some(fe_1_value), Some(fe_2_value)) => Some(fe_1_value.mul(&fe_2_value)),
|
||||
(_, _) => None,
|
||||
};
|
||||
let mul_variable: R1CSVariable = cs
|
||||
.alloc(
|
||||
|| "field multiplication",
|
||||
|| mul_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
cs.enforce(
|
||||
|| "mul = fe_1 * fe_2",
|
||||
|lc| lc + fe_1_variable,
|
||||
|lc| lc + fe_2_variable,
|
||||
|lc| lc + mul_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(mul_value, mul_variable))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_field_div(&mut self, fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
ResolvedValue::FieldElement(fe1.div(&fe2))
|
||||
pub(crate) fn enforce_field_div(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
fe_1: FieldElement<F>,
|
||||
fe_2: FieldElement<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
match (fe_1, fe_2) {
|
||||
// if both constants, then return a constant result
|
||||
(FieldElement::Constant(fe_1_constant), FieldElement::Constant(fe_2_constant)) => {
|
||||
ResolvedValue::FieldElement(FieldElement::Constant(
|
||||
fe_1_constant.div(&fe_2_constant),
|
||||
))
|
||||
}
|
||||
// else, return an allocated result
|
||||
(
|
||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
||||
FieldElement::Constant(fe_2_constant),
|
||||
) => {
|
||||
let div_value: Option<F> = fe_1_value.map(|v| v.div(&fe_2_constant));
|
||||
let div_variable: R1CSVariable = cs
|
||||
.alloc(
|
||||
|| "field division",
|
||||
|| div_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
let fe_2_inverse_value = fe_2_constant.inverse().unwrap();
|
||||
|
||||
cs.enforce(
|
||||
|| "div = fe_1 * fe_2^-1",
|
||||
|lc| lc + fe_1_variable,
|
||||
|lc| lc + (fe_2_inverse_value, CS::one()),
|
||||
|lc| lc + div_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(div_value, div_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Constant(fe_1_constant),
|
||||
FieldElement::Allocated(fe_2_value, _fe_2_variable),
|
||||
) => {
|
||||
let div_value: Option<F> = fe_2_value.map(|v| fe_1_constant.div(&v));
|
||||
let div_variable: R1CSVariable = cs
|
||||
.alloc(
|
||||
|| "field division",
|
||||
|| div_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
let fe_2_inverse_value = fe_2_value.map(|v| v.inverse().unwrap());
|
||||
let fe_2_inverse_variable = cs
|
||||
.alloc(
|
||||
|| "field inverse",
|
||||
|| fe_2_inverse_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
cs.enforce(
|
||||
|| "div = fe_1 * fe_2^-1",
|
||||
|lc| lc + (fe_1_constant, CS::one()),
|
||||
|lc| lc + fe_2_inverse_variable,
|
||||
|lc| lc + div_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(div_value, div_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
||||
FieldElement::Allocated(fe_2_value, _fe_2_variable),
|
||||
) => {
|
||||
let div_value: Option<F> = match (fe_1_value, fe_2_value) {
|
||||
(Some(fe_1_value), Some(fe_2_value)) => Some(fe_1_value.div(&fe_2_value)),
|
||||
(_, _) => None,
|
||||
};
|
||||
let div_variable: R1CSVariable = cs
|
||||
.alloc(
|
||||
|| "field division",
|
||||
|| div_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
let fe_2_inverse_value = fe_2_value.map(|v| v.inverse().unwrap());
|
||||
let fe_2_inverse_variable = cs
|
||||
.alloc(
|
||||
|| "field inverse",
|
||||
|| fe_2_inverse_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
cs.enforce(
|
||||
|| "div = fe_1 * fe_2^-1",
|
||||
|lc| lc + fe_1_variable,
|
||||
|lc| lc + fe_2_inverse_variable,
|
||||
|lc| lc + div_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(div_value, div_variable))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_field_pow(&mut self, fe1: F, num: UInt32) -> ResolvedValue<F> {
|
||||
ResolvedValue::FieldElement(fe1.pow(&[num.value.unwrap() as u64]))
|
||||
pub(crate) fn enforce_field_pow(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
fe_1: FieldElement<F>,
|
||||
num: UInt32,
|
||||
) -> ResolvedValue<F> {
|
||||
match fe_1 {
|
||||
// if both constants, then return a constant result
|
||||
FieldElement::Constant(fe_1_constant) => ResolvedValue::FieldElement(
|
||||
FieldElement::Constant(fe_1_constant.pow(&[num.value.unwrap() as u64])),
|
||||
),
|
||||
// else, return an allocated result
|
||||
FieldElement::Allocated(fe_1_value, _fe_1_variable) => {
|
||||
let pow_value: Option<F> = fe_1_value.map(|v| v.pow(&[num.value.unwrap() as u64]));
|
||||
let pow_variable: R1CSVariable = cs
|
||||
.alloc(
|
||||
|| "field exponentiation",
|
||||
|| pow_value.ok_or(SynthesisError::AssignmentMissing),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// cs.enforce( //todo: find a linear combination for this
|
||||
// || "pow = 1 + fe_1^num",
|
||||
// |lc| lc + fe_1_variable,
|
||||
// |lc| lc + (fe_2_inverse_value, CS::one()),
|
||||
// |lc| lc + pow_variable.clone());
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(pow_value, pow_variable))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
//! Methods to enforce constraints on integers in a resolved aleo program.
|
||||
|
||||
use crate::constraints::{ResolvedProgram, ResolvedValue};
|
||||
use crate::{new_variable_from_variable, Integer, Parameter, Variable};
|
||||
use crate::{new_variable_from_variable, Integer, ParameterModel, ParameterValue, Variable};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
use snarkos_models::gadgets::utilities::eq::EqGadget;
|
||||
use snarkos_models::gadgets::{
|
||||
@ -15,34 +16,33 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
scope: String,
|
||||
index: usize,
|
||||
parameter: Parameter<F>,
|
||||
parameter_model: ParameterModel<F>,
|
||||
parameter_value: Option<ParameterValue<F>>,
|
||||
) -> Variable<F> {
|
||||
// Get command line argument for each parameter in program
|
||||
let argument = std::env::args()
|
||||
.nth(index)
|
||||
.expect(&format!(
|
||||
"expected command line argument at index {}",
|
||||
index
|
||||
))
|
||||
.parse::<u32>()
|
||||
.expect(&format!(
|
||||
"expected main function parameter {} at index {}",
|
||||
parameter, index
|
||||
));
|
||||
// Check that the parameter value is the correct type
|
||||
let integer_option = parameter_value.map(|parameter| match parameter {
|
||||
ParameterValue::Integer(i) => i as u32,
|
||||
value => unimplemented!("expected integer parameter, got {}", value),
|
||||
});
|
||||
|
||||
// Check visibility of parameter
|
||||
let name = parameter.variable.name.clone();
|
||||
let number = if parameter.private {
|
||||
UInt32::alloc(cs.ns(|| name), || Ok(argument)).unwrap()
|
||||
let name = parameter_model.variable.name.clone();
|
||||
let integer = if parameter_model.private {
|
||||
UInt32::alloc(cs.ns(|| name), || {
|
||||
integer_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.unwrap()
|
||||
} else {
|
||||
UInt32::alloc_input(cs.ns(|| name), || Ok(argument)).unwrap()
|
||||
UInt32::alloc_input(cs.ns(|| name), || {
|
||||
integer_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let parameter_variable = new_variable_from_variable(scope, ¶meter.variable);
|
||||
let parameter_variable = new_variable_from_variable(scope, ¶meter_model.variable);
|
||||
|
||||
// store each argument as variable in resolved program
|
||||
self.store_variable(parameter_variable.clone(), ResolvedValue::U32(number));
|
||||
self.store_variable(parameter_variable.clone(), ResolvedValue::U32(integer));
|
||||
|
||||
parameter_variable
|
||||
}
|
||||
@ -51,23 +51,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
&mut self,
|
||||
_cs: &mut CS,
|
||||
_scope: String,
|
||||
_index: usize,
|
||||
_parameter: Parameter<F>,
|
||||
_parameter_model: ParameterModel<F>,
|
||||
_parameter_value: Option<ParameterValue<F>>,
|
||||
) -> Variable<F> {
|
||||
unimplemented!("Cannot enforce integer array as parameter")
|
||||
// Get command line argument for each parameter in program
|
||||
// let argument_array = std::env::args()
|
||||
// .nth(index)
|
||||
// .expect(&format!(
|
||||
// "expected command line argument at index {}",
|
||||
// index
|
||||
// ))
|
||||
// .parse::<Vec<u32>>()
|
||||
// .expect(&format!(
|
||||
// "expected main function parameter {} at index {}",
|
||||
// parameter, index
|
||||
// ));
|
||||
//
|
||||
// // Check visibility of parameter
|
||||
// let mut array_value = vec![];
|
||||
// let name = parameter.variable.name.clone();
|
||||
|
@ -3,16 +3,39 @@
|
||||
use crate::types::{Function, Struct, Type, Variable};
|
||||
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
use snarkos_models::gadgets::{utilities::boolean::Boolean, utilities::uint32::UInt32};
|
||||
use snarkos_models::gadgets::{
|
||||
r1cs::Variable as R1CSVariable, utilities::boolean::Boolean, utilities::uint32::UInt32,
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct ResolvedStructMember<F: Field + PrimeField>(pub Variable<F>, pub ResolvedValue<F>);
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum FieldElement<F: Field + PrimeField> {
|
||||
Constant(F),
|
||||
Allocated(Option<F>, R1CSVariable),
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> fmt::Display for FieldElement<F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
FieldElement::Constant(ref constant) => write!(f, "{}", constant),
|
||||
FieldElement::Allocated(ref option, ref _r1cs_var) => {
|
||||
if option.is_some() {
|
||||
write!(f, "{}", option.unwrap())
|
||||
} else {
|
||||
write!(f, "allocated fe")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum ResolvedValue<F: Field + PrimeField> {
|
||||
U32(UInt32),
|
||||
FieldElement(F),
|
||||
FieldElement(FieldElement<F>),
|
||||
Boolean(Boolean),
|
||||
Array(Vec<ResolvedValue<F>>),
|
||||
StructDefinition(Struct<F>),
|
||||
@ -24,9 +47,9 @@ pub enum ResolvedValue<F: Field + PrimeField> {
|
||||
impl<F: Field + PrimeField> ResolvedValue<F> {
|
||||
pub(crate) fn match_type(&self, ty: &Type<F>) -> bool {
|
||||
match (self, ty) {
|
||||
(ResolvedValue::U32(ref _a), Type::U32) => true,
|
||||
(ResolvedValue::FieldElement(ref _a), Type::FieldElement) => true,
|
||||
(ResolvedValue::Boolean(ref _a), Type::Boolean) => true,
|
||||
(ResolvedValue::U32(ref _i), Type::U32) => true,
|
||||
(ResolvedValue::FieldElement(ref _f), Type::FieldElement) => true,
|
||||
(ResolvedValue::Boolean(ref _b), Type::Boolean) => true,
|
||||
(ResolvedValue::Array(ref arr), Type::Array(ref ty, ref len)) => {
|
||||
// check array lengths are equal
|
||||
let mut res = arr.len() == *len;
|
||||
|
@ -300,6 +300,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
value => unimplemented!("if else conditional must resolve to boolean, got {}", value),
|
||||
};
|
||||
|
||||
// use gadget impl
|
||||
if condition.eq(&Boolean::Constant(true)) {
|
||||
self.iterate_or_early_return(
|
||||
cs,
|
||||
@ -373,16 +374,18 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
right: ResolvedValue<F>,
|
||||
) {
|
||||
match (left, right) {
|
||||
(ResolvedValue::Boolean(bool1), ResolvedValue::Boolean(bool2)) => {
|
||||
self.enforce_boolean_eq(cs, bool1, bool2)
|
||||
(ResolvedValue::Boolean(bool_1), ResolvedValue::Boolean(bool_2)) => {
|
||||
self.enforce_boolean_eq(cs, bool_1, bool_2)
|
||||
}
|
||||
(ResolvedValue::U32(num1), ResolvedValue::U32(num2)) => {
|
||||
Self::enforce_u32_eq(cs, num1, num2)
|
||||
(ResolvedValue::U32(num_1), ResolvedValue::U32(num_2)) => {
|
||||
Self::enforce_u32_eq(cs, num_1, num_2)
|
||||
}
|
||||
(ResolvedValue::FieldElement(fe1), ResolvedValue::FieldElement(fe2)) => {
|
||||
self.enforce_field_eq(cs, fe1, fe2)
|
||||
(ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
self.enforce_field_eq(cs, fe_1, fe_2)
|
||||
}
|
||||
(val_1, val_2) => {
|
||||
unimplemented!("cannot enforce equality between {} == {}", val_1, val_2)
|
||||
}
|
||||
(val1, val2) => unimplemented!("cannot enforce equality between {} == {}", val1, val2),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,10 +2,6 @@ use crate::Variable;
|
||||
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
|
||||
type ImportPath<'ast> = &'ast Path;
|
||||
// pub(crate) type Variable<'ast = &'ast str;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ImportSymbol<F: Field + PrimeField> {
|
||||
@ -14,28 +10,43 @@ pub struct ImportSymbol<F: Field + PrimeField> {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Import<'ast, F: Field + PrimeField> {
|
||||
pub(crate) source: ImportPath<'ast>,
|
||||
pub(crate) symbols: Vec<ImportSymbol<F>>,
|
||||
pub struct Import<F: Field + PrimeField> {
|
||||
pub path_string: String,
|
||||
pub symbols: Vec<ImportSymbol<F>>,
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField> Import<'ast, F> {
|
||||
pub fn new(source: ImportPath<'ast>, symbols: Vec<ImportSymbol<F>>) -> Import<'ast, F> {
|
||||
Import { source, symbols }
|
||||
impl<F: Field + PrimeField> Import<F> {
|
||||
pub fn new(source: String, symbols: Vec<ImportSymbol<F>>) -> Import<F> {
|
||||
Import {
|
||||
path_string: source,
|
||||
symbols,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_source(&self) -> &Path {
|
||||
&self.source
|
||||
}
|
||||
|
||||
pub fn get_file(&self) -> String {
|
||||
let path = self.get_source().to_str().unwrap();
|
||||
format!("{}.leo", path)
|
||||
pub fn path_string_full(&self) -> String {
|
||||
format!("{}.leo", self.path_string)
|
||||
}
|
||||
|
||||
// from "./import" import *;
|
||||
pub fn is_star(&self) -> bool {
|
||||
self.symbols.is_empty()
|
||||
}
|
||||
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "from {} import ", self.path_string)?;
|
||||
if self.symbols.is_empty() {
|
||||
write!(f, "*")
|
||||
} else {
|
||||
write!(f, "{{\n")?;
|
||||
for (i, symbol) in self.symbols.iter().enumerate() {
|
||||
write!(f, "{}", symbol)?;
|
||||
if i < self.symbols.len() - 1 {
|
||||
write!(f, ",\n")?;
|
||||
}
|
||||
}
|
||||
write!(f, "\n}}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> fmt::Display for ImportSymbol<F> {
|
||||
@ -48,38 +59,14 @@ impl<F: Field + PrimeField> fmt::Display for ImportSymbol<F> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField> fmt::Display for Import<'ast, F> {
|
||||
impl<'ast, F: Field + PrimeField> fmt::Display for Import<F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "from {} import ", self.source.display())?;
|
||||
if self.symbols.is_empty() {
|
||||
write!(f, "*")
|
||||
} else {
|
||||
write!(f, "{{\n")?;
|
||||
for (i, symbol) in self.symbols.iter().enumerate() {
|
||||
write!(f, "{}", symbol)?;
|
||||
if i < self.symbols.len() - 1 {
|
||||
write!(f, ",\n")?;
|
||||
}
|
||||
}
|
||||
write!(f, "\n}}")
|
||||
}
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField> fmt::Debug for Import<'ast, F> {
|
||||
impl<'ast, F: Field + PrimeField> fmt::Debug for Import<F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "from {} import ", self.source.display())?;
|
||||
if self.symbols.is_empty() {
|
||||
write!(f, "*")
|
||||
} else {
|
||||
write!(f, "{{\n")?;
|
||||
for (i, symbol) in self.symbols.iter().enumerate() {
|
||||
write!(f, "{}", symbol)?;
|
||||
if i < self.symbols.len() - 1 {
|
||||
write!(f, ",\n")?;
|
||||
}
|
||||
}
|
||||
write!(f, "\n}}")
|
||||
}
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
@ -155,12 +155,19 @@ pub struct Struct<F: Field + PrimeField> {
|
||||
/// Function parameters
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Parameter<F: Field + PrimeField> {
|
||||
pub struct ParameterModel<F: Field + PrimeField> {
|
||||
pub private: bool,
|
||||
pub ty: Type<F>,
|
||||
pub variable: Variable<F>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum ParameterValue<F: Field + PrimeField> {
|
||||
Integer(usize),
|
||||
Field(F),
|
||||
Boolean(bool),
|
||||
}
|
||||
|
||||
/// The given name for a defined function in the program.
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct FunctionName(pub String);
|
||||
@ -168,7 +175,7 @@ pub struct FunctionName(pub String);
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Function<F: Field + PrimeField> {
|
||||
pub function_name: FunctionName,
|
||||
pub parameters: Vec<Parameter<F>>,
|
||||
pub parameters: Vec<ParameterModel<F>>,
|
||||
pub returns: Vec<Type<F>>,
|
||||
pub statements: Vec<Statement<F>>,
|
||||
}
|
||||
@ -181,14 +188,28 @@ impl<F: Field + PrimeField> Function<F> {
|
||||
|
||||
/// A simple program with statement expressions, program arguments and program returns.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Program<'ast, F: Field + PrimeField> {
|
||||
pub struct Program<F: Field + PrimeField> {
|
||||
pub name: Variable<F>,
|
||||
pub imports: Vec<Import<'ast, F>>,
|
||||
pub num_parameters: usize,
|
||||
pub imports: Vec<Import<F>>,
|
||||
pub structs: HashMap<Variable<F>, Struct<F>>,
|
||||
pub functions: HashMap<FunctionName, Function<F>>,
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField> Program<'ast, F> {
|
||||
impl<'ast, F: Field + PrimeField> Program<F> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
name: Variable {
|
||||
name: "".into(),
|
||||
_field: PhantomData::<F>,
|
||||
},
|
||||
num_parameters: 0,
|
||||
imports: vec![],
|
||||
structs: HashMap::new(),
|
||||
functions: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> String {
|
||||
self.name.name.clone()
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
use crate::{
|
||||
Assignee, ConditionalNestedOrEnd, ConditionalStatement, Expression, Function, FunctionName,
|
||||
Integer, Parameter, RangeOrExpression, SpreadOrExpression, Statement, Struct, StructField,
|
||||
Type, Variable,
|
||||
Integer, ParameterModel, ParameterValue, RangeOrExpression, SpreadOrExpression, Statement,
|
||||
Struct, StructField, Type, Variable,
|
||||
};
|
||||
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
@ -185,7 +185,7 @@ impl<F: Field + PrimeField> fmt::Display for Statement<F> {
|
||||
write!(f, ")\n")
|
||||
}
|
||||
Statement::Definition(ref assignee, ref ty, ref expression) => match ty {
|
||||
Some(ref ty) => write!(f, "let {} : {} = {};", assignee, ty, expression),
|
||||
Some(ref ty) => write!(f, "let {}: {} = {};", assignee, ty, expression),
|
||||
None => write!(f, "let {} = {};", assignee, expression),
|
||||
},
|
||||
Statement::Assign(ref variable, ref statement) => {
|
||||
@ -257,13 +257,23 @@ impl<F: Field + PrimeField> fmt::Debug for Struct<F> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> fmt::Display for Parameter<F> {
|
||||
impl<F: Field + PrimeField> fmt::Display for ParameterModel<F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let visibility = if self.private { "private" } else { "public" };
|
||||
write!(f, "{}: {} {}", self.variable, visibility, self.ty,)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> fmt::Display for ParameterValue<F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
ParameterValue::Integer(ref integer) => write!(f, "{}", integer),
|
||||
ParameterValue::Field(ref field) => write!(f, "{}", field),
|
||||
ParameterValue::Boolean(ref bool) => write!(f, "{}", bool),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FunctionName {
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
|
@ -1,12 +1,11 @@
|
||||
//! Logic to convert from an abstract syntax tree (ast) representation to a typed aleo program.
|
||||
|
||||
use crate::ast;
|
||||
use crate::{ast, FunctionName};
|
||||
use crate::{types, Import, ImportSymbol};
|
||||
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
use std::collections::HashMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::path::Path;
|
||||
|
||||
/// pest ast -> types::Variable
|
||||
|
||||
@ -618,7 +617,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Struct<'ast>> for types::Struct<F> {
|
||||
|
||||
/// pest ast -> function types::Parameters
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::Parameter<'ast>> for types::Parameter<F> {
|
||||
impl<'ast, F: Field + PrimeField> From<ast::Parameter<'ast>> for types::ParameterModel<F> {
|
||||
fn from(parameter: ast::Parameter<'ast>) -> Self {
|
||||
let ty = types::Type::from(parameter.ty);
|
||||
let variable = types::Variable::from(parameter.variable);
|
||||
@ -628,13 +627,13 @@ impl<'ast, F: Field + PrimeField> From<ast::Parameter<'ast>> for types::Paramete
|
||||
ast::Visibility::Private(_) => true,
|
||||
ast::Visibility::Public(_) => false,
|
||||
};
|
||||
types::Parameter {
|
||||
types::ParameterModel {
|
||||
private,
|
||||
ty,
|
||||
variable,
|
||||
}
|
||||
} else {
|
||||
types::Parameter {
|
||||
types::ParameterModel {
|
||||
private: true,
|
||||
ty,
|
||||
variable,
|
||||
@ -657,7 +656,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Function<'ast>> for types::Function<
|
||||
let parameters = function_definition
|
||||
.parameters
|
||||
.into_iter()
|
||||
.map(|parameter| types::Parameter::from(parameter))
|
||||
.map(|parameter| types::ParameterModel::from(parameter))
|
||||
.collect();
|
||||
let returns = function_definition
|
||||
.returns
|
||||
@ -690,10 +689,10 @@ impl<'ast, F: Field + PrimeField> From<ast::ImportSymbol<'ast>> for ImportSymbol
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::Import<'ast>> for Import<'ast, F> {
|
||||
impl<'ast, F: Field + PrimeField> From<ast::Import<'ast>> for Import<F> {
|
||||
fn from(import: ast::Import<'ast>) -> Self {
|
||||
Import {
|
||||
source: Path::new(import.source.span.as_str()),
|
||||
path_string: import.source.value,
|
||||
symbols: import
|
||||
.symbols
|
||||
.into_iter()
|
||||
@ -705,17 +704,18 @@ impl<'ast, F: Field + PrimeField> From<ast::Import<'ast>> for Import<'ast, F> {
|
||||
|
||||
/// pest ast -> types::Program
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::File<'ast>> for types::Program<'ast, F> {
|
||||
fn from(file: ast::File<'ast>) -> Self {
|
||||
impl<'ast, F: Field + PrimeField> types::Program<F> {
|
||||
pub fn from(file: ast::File<'ast>, name: String) -> Self {
|
||||
// Compiled ast -> aleo program representation
|
||||
let imports = file
|
||||
.imports
|
||||
.into_iter()
|
||||
.map(|import| Import::from(import))
|
||||
.collect::<Vec<Import<'ast, F>>>();
|
||||
.collect::<Vec<Import<F>>>();
|
||||
|
||||
let mut structs = HashMap::new();
|
||||
let mut functions = HashMap::new();
|
||||
let mut num_parameters = 0usize;
|
||||
|
||||
file.structs.into_iter().for_each(|struct_def| {
|
||||
structs.insert(
|
||||
@ -730,11 +730,16 @@ impl<'ast, F: Field + PrimeField> From<ast::File<'ast>> for types::Program<'ast,
|
||||
);
|
||||
});
|
||||
|
||||
if let Some(main_function) = functions.get(&FunctionName("main".into())) {
|
||||
num_parameters = main_function.parameters.len();
|
||||
}
|
||||
|
||||
types::Program {
|
||||
name: types::Variable {
|
||||
name: "".into(),
|
||||
name,
|
||||
_field: PhantomData::<F>,
|
||||
},
|
||||
num_parameters,
|
||||
imports,
|
||||
structs,
|
||||
functions,
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::{cli::*, cli_types::*};
|
||||
use crate::directories::{source::SOURCE_DIRECTORY_NAME, OutputsDirectory};
|
||||
use crate::errors::{BuildError, CLIError};
|
||||
use crate::files::{MainFile, MAIN_FILE_NAME, ChecksumFile};
|
||||
use crate::files::{ChecksumFile, MainFile, MAIN_FILE_NAME};
|
||||
use crate::manifest::Manifest;
|
||||
use crate::{cli::*, cli_types::*};
|
||||
use leo_compiler::compiler::Compiler;
|
||||
|
||||
use snarkos_algorithms::snark::KeypairAssembly;
|
||||
@ -61,7 +61,7 @@ impl CLI for BuildCommand {
|
||||
main_file_path.push(MAIN_FILE_NAME);
|
||||
|
||||
// Compute the current program checksum
|
||||
let program = Compiler::<Fr>::init(package_name.clone(), main_file_path.clone());
|
||||
let mut program = Compiler::<Fr>::init(package_name.clone(), main_file_path.clone());
|
||||
let checksum = program.checksum()?;
|
||||
|
||||
// If a checksum file exists, check if it differs from the new checksum
|
||||
@ -80,15 +80,15 @@ impl CLI for BuildCommand {
|
||||
checksum_file.write_to(&path, checksum)?;
|
||||
|
||||
// Generate the program on the constraint system and verify correctness
|
||||
let mut cs = KeypairAssembly::<Bls12_377> {
|
||||
num_inputs: 0,
|
||||
num_aux: 0,
|
||||
num_constraints: 0,
|
||||
at: vec![],
|
||||
bt: vec![],
|
||||
ct: vec![],
|
||||
};
|
||||
program.evaluate_program(&mut cs)?;
|
||||
// let mut cs = KeypairAssembly::<Bls12_377> {
|
||||
// num_inputs: 0,
|
||||
// num_aux: 0,
|
||||
// num_constraints: 0,
|
||||
// at: vec![],
|
||||
// bt: vec![],
|
||||
// ct: vec![],
|
||||
// };
|
||||
program.evaluate_program::<KeypairAssembly::<Bls12_377>>()?;
|
||||
}
|
||||
|
||||
log::info!("Compiled program in {:?}", main_file_path);
|
||||
|
Loading…
Reference in New Issue
Block a user