1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use crate::{
errors::FunctionError,
program::{new_scope, ConstrainedProgram},
value::ConstrainedValue,
GroupType,
};
use leo_typed::{Expression, Function, InputVariable, Span, Type};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
pub fn check_arguments_length(expected: usize, actual: usize, span: Span) -> Result<(), FunctionError> {
if expected != actual {
Err(FunctionError::arguments_length(expected, actual, span))
} else {
Ok(())
}
}
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub(crate) fn enforce_function<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
scope: String,
caller_scope: String,
function: Function,
input: Vec<Expression>,
) -> Result<ConstrainedValue<F, G>, FunctionError> {
let function_name = new_scope(scope.clone(), function.get_name());
check_arguments_length(function.input.len(), input.len(), function.span.clone())?;
for (input_model, input_expression) in function.input.clone().iter().zip(input.into_iter()) {
let (name, value) = match input_model {
InputVariable::InputKeyword(identifier) => {
let input_value = self.enforce_function_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
None,
input_expression,
)?;
(identifier.name.clone(), input_value)
}
InputVariable::FunctionInput(input_model) => {
let mut input_value = self.enforce_function_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
Some(input_model.type_.clone()),
input_expression,
)?;
if input_model.mutable {
input_value = ConstrainedValue::Mutable(Box::new(input_value))
}
(input_model.identifier.name.clone(), input_value)
}
};
let input_program_identifier = new_scope(function_name.clone(), name);
self.store(input_program_identifier, value);
}
let mut results = vec![];
for statement in function.statements.iter() {
let mut result = self.enforce_statement(
cs,
scope.clone(),
function_name.clone(),
None,
statement.clone(),
function.returns.clone(),
)?;
results.append(&mut result);
}
let mut return_values = ConstrainedValue::Tuple(vec![]);
Self::conditionally_select_result(cs, &mut return_values, results, function.span.clone())?;
if let ConstrainedValue::Tuple(ref returns) = return_values {
let return_types = match function.returns {
Some(Type::Tuple(types)) => types.len(),
Some(_) => 1usize,
None => 0usize,
};
if return_types != returns.len() {
return Err(FunctionError::return_arguments_length(
return_types,
returns.len(),
function.span.clone(),
));
}
}
Ok(return_values)
}
}