mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-23 10:12:21 +03:00
refactor integer module, add uint8 type
This commit is contained in:
parent
dcd484a62f
commit
73e431e9eb
@ -1,15 +1,6 @@
|
||||
struct Foo {
|
||||
x: u32
|
||||
y: u32
|
||||
}
|
||||
|
||||
function main(a: private fe) {
|
||||
let b = a + 1fe;
|
||||
assert_eq(b, 2fe);
|
||||
|
||||
let c = Foo {
|
||||
x: 4,
|
||||
y: 5,
|
||||
};
|
||||
function main() {
|
||||
let a = 1u8 + 2u8;
|
||||
let b = 2u32 + 4;
|
||||
|
||||
assert_eq(b, 6);
|
||||
}
|
@ -60,7 +60,7 @@ impl<F: Field + PrimeField> ConstraintSynthesizer<F> for Benchmark<F> {
|
||||
cs: &mut CS,
|
||||
) -> Result<(), SynthesisError> {
|
||||
let _res =
|
||||
leo_compiler::ResolvedProgram::generate_constraints(cs, self.program, self.parameters);
|
||||
leo_compiler::ConstrainedProgram::generate_constraints(cs, self.program, self.parameters);
|
||||
println!(" Result: {}", _res);
|
||||
|
||||
// Write results to file or something
|
||||
@ -92,8 +92,8 @@ fn main() {
|
||||
let start = Instant::now();
|
||||
|
||||
// Set main function arguments in compiled program
|
||||
let argument = Some(ParameterValue::Field(Fr::one()));
|
||||
program.parameters = vec![argument];
|
||||
// let argument = Some(ParameterValue::Field(Fr::one()));
|
||||
// program.parameters = vec![argument];
|
||||
|
||||
// Generate proof
|
||||
let proof = create_random_proof(program, ¶ms, rng).unwrap();
|
||||
|
@ -122,11 +122,19 @@ pub enum OperationAssign {
|
||||
|
||||
// Types
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::type_u8))]
|
||||
pub struct U8Type {}
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::type_u32))]
|
||||
pub struct U32Type<'ast> {
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
pub struct U32Type {}
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::type_integer))]
|
||||
pub enum IntegerType {
|
||||
U8Type(U8Type),
|
||||
U32Type(U32Type),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
@ -154,7 +162,7 @@ pub struct StructType<'ast> {
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::type_basic))]
|
||||
pub enum BasicType<'ast> {
|
||||
U32(U32Type<'ast>),
|
||||
Integer(IntegerType),
|
||||
Field(FieldType<'ast>),
|
||||
Boolean(BooleanType<'ast>),
|
||||
}
|
||||
@ -210,15 +218,15 @@ impl<'ast> fmt::Display for Number<'ast> {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::value_u32))]
|
||||
pub struct U32<'ast> {
|
||||
#[pest_ast(rule(Rule::value_integer))]
|
||||
pub struct Integer<'ast> {
|
||||
pub number: Number<'ast>,
|
||||
pub _type: Option<U32Type<'ast>>,
|
||||
pub _type: Option<IntegerType>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for U32<'ast> {
|
||||
impl<'ast> fmt::Display for Integer<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.number)
|
||||
}
|
||||
@ -257,15 +265,15 @@ impl<'ast> fmt::Display for Boolean<'ast> {
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::value))]
|
||||
pub enum Value<'ast> {
|
||||
Integer(Integer<'ast>),
|
||||
Field(Field<'ast>),
|
||||
Boolean(Boolean<'ast>),
|
||||
U32(U32<'ast>),
|
||||
}
|
||||
|
||||
impl<'ast> Value<'ast> {
|
||||
pub fn span(&self) -> &Span<'ast> {
|
||||
match self {
|
||||
Value::U32(value) => &value.span,
|
||||
Value::Integer(value) => &value.span,
|
||||
Value::Field(value) => &value.span,
|
||||
Value::Boolean(value) => &value.span,
|
||||
}
|
||||
@ -275,7 +283,7 @@ impl<'ast> Value<'ast> {
|
||||
impl<'ast> fmt::Display for Value<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Value::U32(ref value) => write!(f, "{}", value),
|
||||
Value::Integer(ref value) => write!(f, "{}", value),
|
||||
Value::Field(ref value) => write!(f, "{}", value),
|
||||
Value::Boolean(ref value) => write!(f, "{}", value),
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
//! Compiles a Leo program from a file path.
|
||||
|
||||
use crate::{ast, errors::CompilerError, ParameterValue, Program, ResolvedProgram, ResolvedValue};
|
||||
use crate::{
|
||||
ast, errors::CompilerError, ConstrainedProgram, ConstrainedValue, ParameterValue, Program,
|
||||
};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use snarkos_models::{
|
||||
@ -18,7 +20,7 @@ pub struct Compiler<F: Field + PrimeField> {
|
||||
main_file_path: PathBuf,
|
||||
program: Program<F>,
|
||||
parameters: Vec<Option<ParameterValue<F>>>,
|
||||
output: Option<ResolvedValue<F>>,
|
||||
output: Option<ConstrainedValue<F>>,
|
||||
_engine: PhantomData<F>,
|
||||
}
|
||||
|
||||
@ -91,7 +93,7 @@ impl<F: Field + PrimeField> ConstraintSynthesizer<F> for Compiler<F> {
|
||||
self,
|
||||
cs: &mut CS,
|
||||
) -> Result<(), SynthesisError> {
|
||||
let _res = ResolvedProgram::generate_constraints(cs, self.program, self.parameters);
|
||||
let _res = ConstrainedProgram::generate_constraints(cs, self.program, self.parameters);
|
||||
|
||||
// Write results to file or something
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Methods to enforce constraints on booleans in a resolved Leo program.
|
||||
|
||||
use crate::{
|
||||
constraints::{new_variable_from_variable, ResolvedProgram, ResolvedValue},
|
||||
constraints::{new_variable_from_variable, ConstrainedProgram, ConstrainedValue},
|
||||
types::{ParameterModel, ParameterValue, Variable},
|
||||
};
|
||||
|
||||
@ -14,7 +14,7 @@ use snarkos_models::{
|
||||
},
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
|
||||
pub(crate) fn bool_from_parameter(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
@ -45,7 +45,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
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));
|
||||
self.store_variable(
|
||||
parameter_variable.clone(),
|
||||
ConstrainedValue::Boolean(number),
|
||||
);
|
||||
|
||||
parameter_variable
|
||||
}
|
||||
@ -80,13 +83,13 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
// parameter_variable
|
||||
}
|
||||
|
||||
pub(crate) fn get_boolean_constant(bool: bool) -> ResolvedValue<F> {
|
||||
ResolvedValue::Boolean(Boolean::Constant(bool))
|
||||
pub(crate) fn get_boolean_constant(bool: bool) -> ConstrainedValue<F> {
|
||||
ConstrainedValue::Boolean(Boolean::Constant(bool))
|
||||
}
|
||||
|
||||
pub(crate) fn evaluate_not(value: ResolvedValue<F>) -> ResolvedValue<F> {
|
||||
pub(crate) fn evaluate_not(value: ConstrainedValue<F>) -> ConstrainedValue<F> {
|
||||
match value {
|
||||
ResolvedValue::Boolean(boolean) => ResolvedValue::Boolean(boolean.not()),
|
||||
ConstrainedValue::Boolean(boolean) => ConstrainedValue::Boolean(boolean.not()),
|
||||
value => unimplemented!("cannot enforce not on non-boolean value {}", value),
|
||||
}
|
||||
}
|
||||
@ -94,12 +97,12 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
pub(crate) fn enforce_or(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
left: ResolvedValue<F>,
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
left: ConstrainedValue<F>,
|
||||
right: ConstrainedValue<F>,
|
||||
) -> ConstrainedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::Boolean(left_bool), ResolvedValue::Boolean(right_bool)) => {
|
||||
ResolvedValue::Boolean(Boolean::or(cs, &left_bool, &right_bool).unwrap())
|
||||
(ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) => {
|
||||
ConstrainedValue::Boolean(Boolean::or(cs, &left_bool, &right_bool).unwrap())
|
||||
}
|
||||
(left_value, right_value) => unimplemented!(
|
||||
"cannot enforce or on non-boolean values {} || {}",
|
||||
@ -112,12 +115,12 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
pub(crate) fn enforce_and(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
left: ResolvedValue<F>,
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
left: ConstrainedValue<F>,
|
||||
right: ConstrainedValue<F>,
|
||||
) -> ConstrainedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::Boolean(left_bool), ResolvedValue::Boolean(right_bool)) => {
|
||||
ResolvedValue::Boolean(Boolean::and(cs, &left_bool, &right_bool).unwrap())
|
||||
(ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) => {
|
||||
ConstrainedValue::Boolean(Boolean::and(cs, &left_bool, &right_bool).unwrap())
|
||||
}
|
||||
(left_value, right_value) => unimplemented!(
|
||||
"cannot enforce and on non-boolean values {} && {}",
|
||||
@ -127,8 +130,8 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn boolean_eq(left: Boolean, right: Boolean) -> ResolvedValue<F> {
|
||||
ResolvedValue::Boolean(Boolean::Constant(left.eq(&right)))
|
||||
pub(crate) fn boolean_eq(left: Boolean, right: Boolean) -> ConstrainedValue<F> {
|
||||
ConstrainedValue::Boolean(Boolean::Constant(left.eq(&right)))
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_boolean_eq(&mut self, cs: &mut CS, left: Boolean, right: Boolean) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! An in memory store to keep track of defined names when constraining a Leo program.
|
||||
|
||||
use crate::{constraints::ResolvedValue, types::Variable};
|
||||
use crate::{constraints::ConstrainedValue, types::Variable};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
@ -8,8 +8,8 @@ use snarkos_models::{
|
||||
};
|
||||
use std::{collections::HashMap, marker::PhantomData};
|
||||
|
||||
pub struct ResolvedProgram<F: Field + PrimeField, CS: ConstraintSystem<F>> {
|
||||
pub resolved_names: HashMap<String, ResolvedValue<F>>,
|
||||
pub struct ConstrainedProgram<F: Field + PrimeField, CS: ConstraintSystem<F>> {
|
||||
pub resolved_names: HashMap<String, ConstrainedValue<F>>,
|
||||
pub _cs: PhantomData<CS>,
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ pub fn new_variable_from_variables<F: Field + PrimeField>(
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
resolved_names: HashMap::new(),
|
||||
@ -52,11 +52,11 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn store(&mut self, name: String, value: ResolvedValue<F>) {
|
||||
pub(crate) fn store(&mut self, name: String, value: ConstrainedValue<F>) {
|
||||
self.resolved_names.insert(name, value);
|
||||
}
|
||||
|
||||
pub(crate) fn store_variable(&mut self, variable: Variable<F>, value: ResolvedValue<F>) {
|
||||
pub(crate) fn store_variable(&mut self, variable: Variable<F>, value: ConstrainedValue<F>) {
|
||||
self.store(variable.name, value);
|
||||
}
|
||||
|
||||
@ -68,18 +68,18 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
self.contains_name(&variable.name)
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, name: &String) -> Option<&ResolvedValue<F>> {
|
||||
pub(crate) fn get(&self, name: &String) -> Option<&ConstrainedValue<F>> {
|
||||
self.resolved_names.get(name)
|
||||
}
|
||||
|
||||
pub(crate) fn get_mut(&mut self, name: &String) -> Option<&mut ResolvedValue<F>> {
|
||||
pub(crate) fn get_mut(&mut self, name: &String) -> Option<&mut ConstrainedValue<F>> {
|
||||
self.resolved_names.get_mut(name)
|
||||
}
|
||||
|
||||
pub(crate) fn get_mut_variable(
|
||||
&mut self,
|
||||
variable: &Variable<F>,
|
||||
) -> Option<&mut ResolvedValue<F>> {
|
||||
) -> Option<&mut ConstrainedValue<F>> {
|
||||
self.get_mut(&variable.name)
|
||||
}
|
||||
}
|
@ -1,17 +1,18 @@
|
||||
//! The in memory stored value for a defined name in a resolved Leo program.
|
||||
|
||||
use crate::types::{Function, Struct, Type, Variable};
|
||||
use crate::{
|
||||
constraints::ConstrainedInteger,
|
||||
types::{Function, Struct, Type, Variable},
|
||||
};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{
|
||||
r1cs::Variable as R1CSVariable, utilities::boolean::Boolean, utilities::uint32::UInt32,
|
||||
},
|
||||
gadgets::{r1cs::Variable as R1CSVariable, utilities::boolean::Boolean},
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct ResolvedStructMember<F: Field + PrimeField>(pub Variable<F>, pub ResolvedValue<F>);
|
||||
pub struct ConstrainedStructMember<F: Field + PrimeField>(pub Variable<F>, pub ConstrainedValue<F>);
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum FieldElement<F: Field + PrimeField> {
|
||||
@ -35,55 +36,60 @@ impl<F: Field + PrimeField> fmt::Display for FieldElement<F> {
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum ResolvedValue<F: Field + PrimeField> {
|
||||
U32(UInt32),
|
||||
pub enum ConstrainedValue<F: Field + PrimeField> {
|
||||
Integer(ConstrainedInteger),
|
||||
FieldElement(FieldElement<F>),
|
||||
Boolean(Boolean),
|
||||
Array(Vec<ResolvedValue<F>>),
|
||||
Array(Vec<ConstrainedValue<F>>),
|
||||
StructDefinition(Struct<F>),
|
||||
StructExpression(Variable<F>, Vec<ResolvedStructMember<F>>),
|
||||
StructExpression(Variable<F>, Vec<ConstrainedStructMember<F>>),
|
||||
Function(Function<F>),
|
||||
Return(Vec<ResolvedValue<F>>), // add Null for function returns
|
||||
Return(Vec<ConstrainedValue<F>>), // add Null for function returns
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> ResolvedValue<F> {
|
||||
pub(crate) fn match_type(&self, ty: &Type<F>) -> bool {
|
||||
match (self, ty) {
|
||||
(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)) => {
|
||||
impl<F: Field + PrimeField> ConstrainedValue<F> {
|
||||
pub(crate) fn expect_type(&self, _type: &Type<F>) {
|
||||
match (self, _type) {
|
||||
(ConstrainedValue::Integer(ref integer), Type::IntegerType(ref _type)) => {
|
||||
integer.expect_type(_type)
|
||||
}
|
||||
(ConstrainedValue::FieldElement(ref _f), Type::FieldElement) => {}
|
||||
(ConstrainedValue::Boolean(ref _b), Type::Boolean) => {}
|
||||
(ConstrainedValue::Array(ref arr), Type::Array(ref ty, ref len)) => {
|
||||
// check array lengths are equal
|
||||
let mut res = arr.len() == *len;
|
||||
if arr.len() != *len {
|
||||
unimplemented!("array length {} != {}", arr.len(), *len)
|
||||
}
|
||||
// check each value in array matches
|
||||
for value in arr {
|
||||
res &= value.match_type(ty)
|
||||
value.expect_type(ty)
|
||||
}
|
||||
res
|
||||
}
|
||||
(
|
||||
ResolvedValue::StructExpression(ref actual_name, ref _members),
|
||||
ConstrainedValue::StructExpression(ref actual_name, ref _members),
|
||||
Type::Struct(ref expected_name),
|
||||
) => actual_name == expected_name,
|
||||
(ResolvedValue::Return(ref values), ty) => {
|
||||
let mut res = true;
|
||||
for value in values {
|
||||
res &= value.match_type(ty)
|
||||
) => {
|
||||
if expected_name != actual_name {
|
||||
unimplemented!("expected struct name {} got {}", expected_name, actual_name)
|
||||
}
|
||||
res
|
||||
}
|
||||
(_, _) => false,
|
||||
(ConstrainedValue::Return(ref values), ty) => {
|
||||
for value in values {
|
||||
value.expect_type(ty)
|
||||
}
|
||||
}
|
||||
(value, _type) => unimplemented!("expected type {}, got {}", _type, value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> fmt::Display for ResolvedValue<F> {
|
||||
impl<F: Field + PrimeField> fmt::Display for ConstrainedValue<F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
ResolvedValue::U32(ref value) => write!(f, "{}", value.value.unwrap()),
|
||||
ResolvedValue::FieldElement(ref value) => write!(f, "{}", value),
|
||||
ResolvedValue::Boolean(ref value) => write!(f, "{}", value.get_value().unwrap()),
|
||||
ResolvedValue::Array(ref array) => {
|
||||
ConstrainedValue::Integer(ref value) => write!(f, "{}", value),
|
||||
ConstrainedValue::FieldElement(ref value) => write!(f, "{}", value),
|
||||
ConstrainedValue::Boolean(ref value) => write!(f, "{}", value.get_value().unwrap()),
|
||||
ConstrainedValue::Array(ref array) => {
|
||||
write!(f, "[")?;
|
||||
for (i, e) in array.iter().enumerate() {
|
||||
write!(f, "{}", e)?;
|
||||
@ -93,7 +99,7 @@ impl<F: Field + PrimeField> fmt::Display for ResolvedValue<F> {
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
ResolvedValue::StructExpression(ref variable, ref members) => {
|
||||
ConstrainedValue::StructExpression(ref variable, ref members) => {
|
||||
write!(f, "{} {{", variable)?;
|
||||
for (i, member) in members.iter().enumerate() {
|
||||
write!(f, "{}: {}", member.0, member.1)?;
|
||||
@ -103,7 +109,7 @@ impl<F: Field + PrimeField> fmt::Display for ResolvedValue<F> {
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
ResolvedValue::Return(ref values) => {
|
||||
ConstrainedValue::Return(ref values) => {
|
||||
write!(f, "Program output: [")?;
|
||||
for (i, value) in values.iter().enumerate() {
|
||||
write!(f, "{}", value)?;
|
||||
@ -113,15 +119,15 @@ impl<F: Field + PrimeField> fmt::Display for ResolvedValue<F> {
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
ResolvedValue::StructDefinition(ref _definition) => {
|
||||
ConstrainedValue::StructDefinition(ref _definition) => {
|
||||
unimplemented!("cannot return struct definition in program")
|
||||
}
|
||||
ResolvedValue::Function(ref function) => write!(f, "{}();", function.function_name),
|
||||
ConstrainedValue::Function(ref function) => write!(f, "{}();", function.function_name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> fmt::Debug for ResolvedValue<F> {
|
||||
impl<F: Field + PrimeField> fmt::Debug for ConstrainedValue<F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
}
|
@ -2,8 +2,8 @@
|
||||
|
||||
use crate::{
|
||||
constraints::{
|
||||
new_scope_from_variable, new_variable_from_variable, ResolvedProgram, ResolvedStructMember,
|
||||
ResolvedValue,
|
||||
new_scope_from_variable, new_variable_from_variable, ConstrainedProgram,
|
||||
ConstrainedStructMember, ConstrainedValue,
|
||||
},
|
||||
types::{Expression, RangeOrExpression, SpreadOrExpression, StructMember, Variable},
|
||||
};
|
||||
@ -13,13 +13,13 @@ use snarkos_models::{
|
||||
gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean},
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
|
||||
/// Enforce a variable expression by getting the resolved value
|
||||
pub(crate) fn enforce_variable(
|
||||
&mut self,
|
||||
scope: String,
|
||||
unresolved_variable: Variable<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<F> {
|
||||
// Evaluate the variable name in the current function scope
|
||||
let variable_name = new_scope_from_variable(scope, &unresolved_variable);
|
||||
|
||||
@ -39,14 +39,14 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
fn enforce_add_expression(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
left: ResolvedValue<F>,
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
left: ConstrainedValue<F>,
|
||||
right: ConstrainedValue<F>,
|
||||
) -> ConstrainedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::U32(num_1), ResolvedValue::U32(num_2)) => {
|
||||
Self::enforce_u32_add(cs, num_1, num_2)
|
||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||
Self::enforce_integer_add(cs, num_1, num_2)
|
||||
}
|
||||
(ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
|
||||
self.enforce_field_add(cs, fe_1, fe_2)
|
||||
}
|
||||
(val_1, val_2) => unimplemented!("cannot add {} + {}", val_1, val_2),
|
||||
@ -56,14 +56,14 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
fn enforce_sub_expression(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
left: ResolvedValue<F>,
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
left: ConstrainedValue<F>,
|
||||
right: ConstrainedValue<F>,
|
||||
) -> ConstrainedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::U32(num_1), ResolvedValue::U32(num_2)) => {
|
||||
Self::enforce_u32_sub(cs, num_1, num_2)
|
||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||
Self::enforce_integer_sub(cs, num_1, num_2)
|
||||
}
|
||||
(ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
|
||||
self.enforce_field_sub(cs, fe_1, fe_2)
|
||||
}
|
||||
(val_1, val_2) => unimplemented!("cannot subtract {} - {}", val_1, val_2),
|
||||
@ -73,14 +73,14 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
fn enforce_mul_expression(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
left: ResolvedValue<F>,
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
left: ConstrainedValue<F>,
|
||||
right: ConstrainedValue<F>,
|
||||
) -> ConstrainedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::U32(num_1), ResolvedValue::U32(num_2)) => {
|
||||
Self::enforce_u32_mul(cs, num_1, num_2)
|
||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||
Self::enforce_integer_mul(cs, num_1, num_2)
|
||||
}
|
||||
(ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
|
||||
self.enforce_field_mul(cs, fe_1, fe_2)
|
||||
}
|
||||
(val_1, val_2) => unimplemented!("cannot multiply {} * {}", val_1, val_2),
|
||||
@ -90,14 +90,14 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
fn enforce_div_expression(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
left: ResolvedValue<F>,
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
left: ConstrainedValue<F>,
|
||||
right: ConstrainedValue<F>,
|
||||
) -> ConstrainedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::U32(num_1), ResolvedValue::U32(num_2)) => {
|
||||
Self::enforce_u32_div(cs, num_1, num_2)
|
||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||
Self::enforce_integer_div(cs, num_1, num_2)
|
||||
}
|
||||
(ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
|
||||
self.enforce_field_div(cs, fe_1, fe_2)
|
||||
}
|
||||
(val_1, val_2) => unimplemented!("cannot divide {} / {}", val_1, val_2),
|
||||
@ -106,17 +106,17 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
fn enforce_pow_expression(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
left: ResolvedValue<F>,
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
left: ConstrainedValue<F>,
|
||||
right: ConstrainedValue<F>,
|
||||
) -> ConstrainedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::U32(num_1), ResolvedValue::U32(num_2)) => {
|
||||
Self::enforce_u32_pow(cs, num_1, num_2)
|
||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||
Self::enforce_integer_pow(cs, num_1, num_2)
|
||||
}
|
||||
(ResolvedValue::FieldElement(fe_1), ResolvedValue::U32(num_2)) => {
|
||||
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::Integer(num_2)) => {
|
||||
self.enforce_field_pow(cs, fe_1, num_2)
|
||||
}
|
||||
(_, ResolvedValue::FieldElement(num_2)) => {
|
||||
(_, ConstrainedValue::FieldElement(num_2)) => {
|
||||
unimplemented!("exponent power must be an integer, got field {}", num_2)
|
||||
}
|
||||
(val_1, val_2) => unimplemented!("cannot enforce exponentiation {} * {}", val_1, val_2),
|
||||
@ -126,14 +126,16 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
/// Evaluate Boolean operations
|
||||
fn evaluate_eq_expression(
|
||||
&mut self,
|
||||
left: ResolvedValue<F>,
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
left: ConstrainedValue<F>,
|
||||
right: ConstrainedValue<F>,
|
||||
) -> ConstrainedValue<F> {
|
||||
match (left, right) {
|
||||
(ResolvedValue::Boolean(bool_1), ResolvedValue::Boolean(bool_2)) => {
|
||||
(ConstrainedValue::Boolean(bool_1), ConstrainedValue::Boolean(bool_2)) => {
|
||||
Self::boolean_eq(bool_1, bool_2)
|
||||
}
|
||||
(ResolvedValue::U32(num_1), ResolvedValue::U32(num_2)) => Self::u32_eq(num_1, num_2),
|
||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||
Self::evaluate_integer_eq(num_1, num_2)
|
||||
}
|
||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
// Self::field_eq(fe_1, fe_2)
|
||||
// }
|
||||
@ -143,9 +145,9 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|
||||
fn evaluate_geq_expression(
|
||||
&mut self,
|
||||
left: ResolvedValue<F>,
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
left: ConstrainedValue<F>,
|
||||
right: ConstrainedValue<F>,
|
||||
) -> ConstrainedValue<F> {
|
||||
match (left, right) {
|
||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
// Self::field_geq(fe_1, fe_2)
|
||||
@ -160,9 +162,9 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|
||||
fn evaluate_gt_expression(
|
||||
&mut self,
|
||||
left: ResolvedValue<F>,
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
left: ConstrainedValue<F>,
|
||||
right: ConstrainedValue<F>,
|
||||
) -> ConstrainedValue<F> {
|
||||
match (left, right) {
|
||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
// Self::field_gt(fe_1, fe_2)
|
||||
@ -177,9 +179,9 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|
||||
fn evaluate_leq_expression(
|
||||
&mut self,
|
||||
left: ResolvedValue<F>,
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
left: ConstrainedValue<F>,
|
||||
right: ConstrainedValue<F>,
|
||||
) -> ConstrainedValue<F> {
|
||||
match (left, right) {
|
||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
// Self::field_leq(fe_1, fe_2)
|
||||
@ -194,9 +196,9 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|
||||
fn evaluate_lt_expression(
|
||||
&mut self,
|
||||
left: ResolvedValue<F>,
|
||||
right: ResolvedValue<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
left: ConstrainedValue<F>,
|
||||
right: ConstrainedValue<F>,
|
||||
) -> ConstrainedValue<F> {
|
||||
match (left, right) {
|
||||
// (ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
// Self::field_lt(fe_1, fe_2)
|
||||
@ -216,7 +218,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
array: Vec<Box<SpreadOrExpression<F>>>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<F> {
|
||||
let mut result = vec![];
|
||||
array.into_iter().for_each(|element| match *element {
|
||||
SpreadOrExpression::Spread(spread) => match spread {
|
||||
@ -224,7 +226,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
let array_name = new_scope_from_variable(function_scope.clone(), &variable);
|
||||
match self.get(&array_name) {
|
||||
Some(value) => match value {
|
||||
ResolvedValue::Array(array) => result.extend(array.clone()),
|
||||
ConstrainedValue::Array(array) => result.extend(array.clone()),
|
||||
value => {
|
||||
unimplemented!("spreads only implemented for arrays, got {}", value)
|
||||
}
|
||||
@ -246,7 +248,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
));
|
||||
}
|
||||
});
|
||||
ResolvedValue::Array(result)
|
||||
ConstrainedValue::Array(result)
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_index(
|
||||
@ -257,7 +259,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
index: Expression<F>,
|
||||
) -> usize {
|
||||
match self.enforce_expression(cs, file_scope, function_scope, index) {
|
||||
ResolvedValue::U32(number) => number.value.unwrap() as usize,
|
||||
ConstrainedValue::Integer(number) => number.get_value() as usize,
|
||||
value => unimplemented!("From index must resolve to an integer, got {}", value),
|
||||
}
|
||||
}
|
||||
@ -269,9 +271,9 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function_scope: String,
|
||||
array: Box<Expression<F>>,
|
||||
index: RangeOrExpression<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<F> {
|
||||
match self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), *array) {
|
||||
ResolvedValue::Array(array) => {
|
||||
ConstrainedValue::Array(array) => {
|
||||
match index {
|
||||
RangeOrExpression::Range(from, to) => {
|
||||
let from_resolved = match from {
|
||||
@ -282,7 +284,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
Some(to_index) => to_index.to_usize(),
|
||||
None => array.len(), // Array slice ends at array length
|
||||
};
|
||||
ResolvedValue::Array(array[from_resolved..to_resolved].to_owned())
|
||||
ConstrainedValue::Array(array[from_resolved..to_resolved].to_owned())
|
||||
}
|
||||
RangeOrExpression::Expression(index) => {
|
||||
let index_resolved =
|
||||
@ -302,12 +304,12 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function_scope: String,
|
||||
variable: Variable<F>,
|
||||
members: Vec<StructMember<F>>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<F> {
|
||||
let struct_name = new_variable_from_variable(file_scope.clone(), &variable);
|
||||
|
||||
if let Some(resolved_value) = self.get_mut_variable(&struct_name) {
|
||||
match resolved_value {
|
||||
ResolvedValue::StructDefinition(struct_definition) => {
|
||||
ConstrainedValue::StructDefinition(struct_definition) => {
|
||||
let resolved_members = struct_definition
|
||||
.fields
|
||||
.clone()
|
||||
@ -325,11 +327,11 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
member.expression,
|
||||
);
|
||||
|
||||
ResolvedStructMember(member.variable, member_value)
|
||||
ConstrainedStructMember(member.variable, member_value)
|
||||
})
|
||||
.collect();
|
||||
|
||||
ResolvedValue::StructExpression(variable, resolved_members)
|
||||
ConstrainedValue::StructExpression(variable, resolved_members)
|
||||
}
|
||||
_ => unimplemented!("Inline struct type is not defined as a struct"),
|
||||
}
|
||||
@ -348,9 +350,9 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function_scope: String,
|
||||
struct_variable: Box<Expression<F>>,
|
||||
struct_member: Variable<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<F> {
|
||||
match self.enforce_expression(cs, file_scope, function_scope, *struct_variable) {
|
||||
ResolvedValue::StructExpression(_name, members) => {
|
||||
ConstrainedValue::StructExpression(_name, members) => {
|
||||
let matched_member = members.into_iter().find(|member| member.0 == struct_member);
|
||||
match matched_member {
|
||||
Some(member) => member.1,
|
||||
@ -368,19 +370,19 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function_scope: String,
|
||||
function: Variable<F>,
|
||||
arguments: Vec<Expression<F>>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<F> {
|
||||
let function_name = new_variable_from_variable(file_scope.clone(), &function);
|
||||
match self.get_mut_variable(&function_name) {
|
||||
Some(value) => match value.clone() {
|
||||
ResolvedValue::Function(function) => {
|
||||
ConstrainedValue::Function(function) => {
|
||||
// this function call is inline so we unwrap the return value
|
||||
match self.enforce_function(cs, file_scope, function_scope, function, arguments)
|
||||
{
|
||||
ResolvedValue::Return(return_values) => {
|
||||
ConstrainedValue::Return(return_values) => {
|
||||
if return_values.len() == 1 {
|
||||
return_values[0].clone()
|
||||
} else {
|
||||
ResolvedValue::Return(return_values)
|
||||
ConstrainedValue::Return(return_values)
|
||||
}
|
||||
}
|
||||
value => unimplemented!(
|
||||
@ -402,7 +404,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
expression: Expression<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<F> {
|
||||
match expression {
|
||||
// Variables
|
||||
Expression::Variable(unresolved_variable) => {
|
||||
@ -528,7 +530,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function_scope.clone(),
|
||||
*first,
|
||||
) {
|
||||
ResolvedValue::Boolean(resolved) => resolved,
|
||||
ConstrainedValue::Boolean(resolved) => resolved,
|
||||
_ => unimplemented!("if else conditional must resolve to boolean"),
|
||||
};
|
||||
|
||||
|
@ -1,20 +1,18 @@
|
||||
//! Methods to enforce constraints on field elements in a resolved Leo program.
|
||||
|
||||
use crate::{
|
||||
constraints::{new_variable_from_variable, FieldElement, ResolvedProgram, ResolvedValue},
|
||||
constraints::{new_variable_from_variable, ConstrainedProgram, ConstrainedValue, FieldElement},
|
||||
types::{ParameterModel, ParameterValue, Variable},
|
||||
ConstrainedInteger,
|
||||
};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{
|
||||
r1cs::{ConstraintSystem, LinearCombination, Variable as R1CSVariable},
|
||||
utilities::uint32::UInt32,
|
||||
},
|
||||
gadgets::r1cs::{ConstraintSystem, LinearCombination, Variable as R1CSVariable},
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
|
||||
pub(crate) fn field_element_from_parameter(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
@ -49,7 +47,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
// Store parameter as variable in resolved program
|
||||
self.store_variable(
|
||||
parameter_variable.clone(),
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(field_option, field_value)),
|
||||
ConstrainedValue::FieldElement(FieldElement::Allocated(field_option, field_value)),
|
||||
);
|
||||
|
||||
parameter_variable
|
||||
@ -83,8 +81,8 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
// parameter_variable
|
||||
}
|
||||
|
||||
pub(crate) fn get_field_element_constant(fe: F) -> ResolvedValue<F> {
|
||||
ResolvedValue::FieldElement(FieldElement::Constant(fe))
|
||||
pub(crate) fn get_field_element_constant(fe: F) -> ConstrainedValue<F> {
|
||||
ConstrainedValue::FieldElement(FieldElement::Constant(fe))
|
||||
}
|
||||
|
||||
// pub(crate) fn field_eq(fe1: F, fe2: F) -> ResolvedValue<F> {
|
||||
@ -156,11 +154,11 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
cs: &mut CS,
|
||||
fe_1: FieldElement<F>,
|
||||
fe_2: FieldElement<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<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(
|
||||
ConstrainedValue::FieldElement(FieldElement::Constant(
|
||||
fe_1_constant.add(&fe_2_constant),
|
||||
))
|
||||
}
|
||||
@ -184,7 +182,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|lc| lc + sum_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(sum_value, sum_variable))
|
||||
ConstrainedValue::FieldElement(FieldElement::Allocated(sum_value, sum_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Constant(fe_1_constant),
|
||||
@ -205,7 +203,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|lc| lc + sum_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(sum_value, sum_variable))
|
||||
ConstrainedValue::FieldElement(FieldElement::Allocated(sum_value, sum_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
||||
@ -229,7 +227,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|lc| lc + sum_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(sum_value, sum_variable))
|
||||
ConstrainedValue::FieldElement(FieldElement::Allocated(sum_value, sum_variable))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -239,11 +237,11 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
cs: &mut CS,
|
||||
fe_1: FieldElement<F>,
|
||||
fe_2: FieldElement<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<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(
|
||||
ConstrainedValue::FieldElement(FieldElement::Constant(
|
||||
fe_1_constant.sub(&fe_2_constant),
|
||||
))
|
||||
}
|
||||
@ -267,7 +265,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|lc| lc + sub_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(sub_value, sub_variable))
|
||||
ConstrainedValue::FieldElement(FieldElement::Allocated(sub_value, sub_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Constant(fe_1_constant),
|
||||
@ -288,7 +286,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|lc| lc + sub_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(sub_value, sub_variable))
|
||||
ConstrainedValue::FieldElement(FieldElement::Allocated(sub_value, sub_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
||||
@ -312,7 +310,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|lc| lc + sub_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(sub_value, sub_variable))
|
||||
ConstrainedValue::FieldElement(FieldElement::Allocated(sub_value, sub_variable))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -322,11 +320,11 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
cs: &mut CS,
|
||||
fe_1: FieldElement<F>,
|
||||
fe_2: FieldElement<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<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(
|
||||
ConstrainedValue::FieldElement(FieldElement::Constant(
|
||||
fe_1_constant.mul(&fe_2_constant),
|
||||
))
|
||||
}
|
||||
@ -350,7 +348,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|lc| lc + mul_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(mul_value, mul_variable))
|
||||
ConstrainedValue::FieldElement(FieldElement::Allocated(mul_value, mul_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Constant(fe_1_constant),
|
||||
@ -371,7 +369,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|lc| lc + mul_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(mul_value, mul_variable))
|
||||
ConstrainedValue::FieldElement(FieldElement::Allocated(mul_value, mul_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
||||
@ -395,7 +393,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|lc| lc + mul_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(mul_value, mul_variable))
|
||||
ConstrainedValue::FieldElement(FieldElement::Allocated(mul_value, mul_variable))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -405,11 +403,11 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
cs: &mut CS,
|
||||
fe_1: FieldElement<F>,
|
||||
fe_2: FieldElement<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<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(
|
||||
ConstrainedValue::FieldElement(FieldElement::Constant(
|
||||
fe_1_constant.div(&fe_2_constant),
|
||||
))
|
||||
}
|
||||
@ -434,7 +432,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|lc| lc + div_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(div_value, div_variable))
|
||||
ConstrainedValue::FieldElement(FieldElement::Allocated(div_value, div_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Constant(fe_1_constant),
|
||||
@ -462,7 +460,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|lc| lc + div_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(div_value, div_variable))
|
||||
ConstrainedValue::FieldElement(FieldElement::Allocated(div_value, div_variable))
|
||||
}
|
||||
(
|
||||
FieldElement::Allocated(fe_1_value, fe_1_variable),
|
||||
@ -493,7 +491,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|lc| lc + div_variable.clone(),
|
||||
);
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(div_value, div_variable))
|
||||
ConstrainedValue::FieldElement(FieldElement::Allocated(div_value, div_variable))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -502,16 +500,16 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
fe_1: FieldElement<F>,
|
||||
num: UInt32,
|
||||
) -> ResolvedValue<F> {
|
||||
num: ConstrainedInteger,
|
||||
) -> ConstrainedValue<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])),
|
||||
FieldElement::Constant(fe_1_constant) => ConstrainedValue::FieldElement(
|
||||
FieldElement::Constant(fe_1_constant.pow(&[num.get_value() 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_value: Option<F> = fe_1_value.map(|v| v.pow(&[num.get_value() as u64]));
|
||||
let pow_variable: R1CSVariable = cs
|
||||
.alloc(
|
||||
|| "field exponentiation",
|
||||
@ -525,7 +523,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
// |lc| lc + (fe_2_inverse_value, CS::one()),
|
||||
// |lc| lc + pow_variable.clone());
|
||||
|
||||
ResolvedValue::FieldElement(FieldElement::Allocated(pow_value, pow_variable))
|
||||
ConstrainedValue::FieldElement(FieldElement::Allocated(pow_value, pow_variable))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
244
compiler/src/constraints/integer/integer.rs
Normal file
244
compiler/src/constraints/integer/integer.rs
Normal file
@ -0,0 +1,244 @@
|
||||
//! Methods to enforce constraints on integers in a resolved Leo program.
|
||||
|
||||
use crate::{
|
||||
constraints::{ConstrainedProgram, ConstrainedValue},
|
||||
types::{Integer, ParameterModel, ParameterValue, Type, Variable},
|
||||
IntegerType,
|
||||
};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{
|
||||
r1cs::ConstraintSystem,
|
||||
utilities::{boolean::Boolean, uint32::UInt32, uint8::UInt8},
|
||||
},
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum ConstrainedInteger {
|
||||
U8(UInt8),
|
||||
U32(UInt32),
|
||||
}
|
||||
|
||||
impl ConstrainedInteger {
|
||||
pub(crate) fn get_value(&self) -> usize {
|
||||
match self {
|
||||
ConstrainedInteger::U8(u8) => u8.value.unwrap() as usize,
|
||||
ConstrainedInteger::U32(u32) => u32.value.unwrap() as usize,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn expect_type(&self, integer_type: &IntegerType) {
|
||||
match (self, integer_type) {
|
||||
(ConstrainedInteger::U8(_u8), IntegerType::U8) => {}
|
||||
(ConstrainedInteger::U32(_u32), IntegerType::U32) => {}
|
||||
(actual, expected) => {
|
||||
unimplemented!("expected integer type {}, got {}", expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ConstrainedInteger {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
ConstrainedInteger::U8(u8) => write!(f, "{}", u8.value.unwrap()),
|
||||
ConstrainedInteger::U32(u32) => write!(f, "{}", u32.value.unwrap()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
|
||||
pub(crate) fn get_integer_constant(integer: Integer) -> ConstrainedValue<F> {
|
||||
ConstrainedValue::Integer(match integer {
|
||||
Integer::U8(u8_value) => ConstrainedInteger::U8(UInt8::constant(u8_value)),
|
||||
Integer::U32(u32_value) => ConstrainedInteger::U32(UInt32::constant(u32_value)),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn evaluate_integer_eq(
|
||||
left: ConstrainedInteger,
|
||||
right: ConstrainedInteger,
|
||||
) -> ConstrainedValue<F> {
|
||||
ConstrainedValue::Boolean(Boolean::Constant(match (left, right) {
|
||||
(ConstrainedInteger::U8(left_u8), ConstrainedInteger::U8(right_u8)) => {
|
||||
left_u8.eq(&right_u8)
|
||||
}
|
||||
(ConstrainedInteger::U32(left_u32), ConstrainedInteger::U32(right_u32)) => {
|
||||
left_u32.eq(&right_u32)
|
||||
}
|
||||
(left, right) => unimplemented!(
|
||||
"cannot evaluate integer equality between {} == {}",
|
||||
left,
|
||||
right
|
||||
),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn integer_from_parameter(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
scope: String,
|
||||
parameter_model: ParameterModel<F>,
|
||||
parameter_value: Option<ParameterValue<F>>,
|
||||
) -> Variable<F> {
|
||||
let integer_type = match ¶meter_model._type {
|
||||
Type::IntegerType(integer_type) => integer_type,
|
||||
_type => unimplemented!("expected integer parameter, got {}", _type),
|
||||
};
|
||||
|
||||
match integer_type {
|
||||
IntegerType::U8 => self.u8_from_parameter(cs, scope, parameter_model, parameter_value),
|
||||
IntegerType::U32 => {
|
||||
self.u32_from_parameter(cs, scope, parameter_model, parameter_value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn integer_array_from_parameter(
|
||||
&mut self,
|
||||
_cs: &mut CS,
|
||||
_scope: String,
|
||||
_parameter_model: ParameterModel<F>,
|
||||
_parameter_value: Option<ParameterValue<F>>,
|
||||
) -> Variable<F> {
|
||||
unimplemented!("Cannot enforce integer array as parameter")
|
||||
// // 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 {
|
||||
// UInt32::alloc(cs.ns(|| name), Some(argument)).unwrap()
|
||||
// } else {
|
||||
// UInt32::alloc_input(cs.ns(|| name), Some(argument)).unwrap()
|
||||
// };
|
||||
//
|
||||
// array_value.push(number);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// let parameter_variable = new_variable_from_variable(scope, ¶meter.variable);
|
||||
//
|
||||
// // store array as variable in resolved program
|
||||
// self.store_variable(parameter_variable.clone(), ResolvedValue::U32Array(array_value));
|
||||
//
|
||||
// parameter_variable
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_integer_eq(
|
||||
cs: &mut CS,
|
||||
left: ConstrainedInteger,
|
||||
right: ConstrainedInteger,
|
||||
) {
|
||||
match (left, right) {
|
||||
(ConstrainedInteger::U8(left_u8), ConstrainedInteger::U8(right_u8)) => {
|
||||
Self::enforce_u8_eq(cs, left_u8, right_u8)
|
||||
}
|
||||
(ConstrainedInteger::U32(left_u32), ConstrainedInteger::U32(right_u32)) => {
|
||||
Self::enforce_u32_eq(cs, left_u32, right_u32)
|
||||
}
|
||||
(left, right) => unimplemented!(
|
||||
"cannot enforce integer equality between {} == {}",
|
||||
left,
|
||||
right
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_integer_add(
|
||||
cs: &mut CS,
|
||||
left: ConstrainedInteger,
|
||||
right: ConstrainedInteger,
|
||||
) -> ConstrainedValue<F> {
|
||||
ConstrainedValue::Integer(match (left, right) {
|
||||
(ConstrainedInteger::U8(left_u8), ConstrainedInteger::U8(right_u8)) => {
|
||||
ConstrainedInteger::U8(Self::enforce_u8_add(cs, left_u8, right_u8))
|
||||
}
|
||||
(ConstrainedInteger::U32(left_u32), ConstrainedInteger::U32(right_u32)) => {
|
||||
ConstrainedInteger::U32(Self::enforce_u32_add(cs, left_u32, right_u32))
|
||||
}
|
||||
(left, right) => unimplemented!(
|
||||
"cannot enforce integer addition between {} + {}",
|
||||
left,
|
||||
right
|
||||
),
|
||||
})
|
||||
}
|
||||
pub(crate) fn enforce_integer_sub(
|
||||
cs: &mut CS,
|
||||
left: ConstrainedInteger,
|
||||
right: ConstrainedInteger,
|
||||
) -> ConstrainedValue<F> {
|
||||
ConstrainedValue::Integer(match (left, right) {
|
||||
(ConstrainedInteger::U8(left_u8), ConstrainedInteger::U8(right_u8)) => {
|
||||
ConstrainedInteger::U8(Self::enforce_u8_sub(cs, left_u8, right_u8))
|
||||
}
|
||||
(ConstrainedInteger::U32(left_u32), ConstrainedInteger::U32(right_u32)) => {
|
||||
ConstrainedInteger::U32(Self::enforce_u32_sub(cs, left_u32, right_u32))
|
||||
}
|
||||
(left, right) => unimplemented!(
|
||||
"cannot enforce integer subtraction between {} - {}",
|
||||
left,
|
||||
right
|
||||
),
|
||||
})
|
||||
}
|
||||
pub(crate) fn enforce_integer_mul(
|
||||
cs: &mut CS,
|
||||
left: ConstrainedInteger,
|
||||
right: ConstrainedInteger,
|
||||
) -> ConstrainedValue<F> {
|
||||
ConstrainedValue::Integer(match (left, right) {
|
||||
(ConstrainedInteger::U8(left_u8), ConstrainedInteger::U8(right_u8)) => {
|
||||
ConstrainedInteger::U8(Self::enforce_u8_mul(cs, left_u8, right_u8))
|
||||
}
|
||||
(ConstrainedInteger::U32(left_u32), ConstrainedInteger::U32(right_u32)) => {
|
||||
ConstrainedInteger::U32(Self::enforce_u32_mul(cs, left_u32, right_u32))
|
||||
}
|
||||
(left, right) => unimplemented!(
|
||||
"cannot enforce integer multiplication between {} * {}",
|
||||
left,
|
||||
right
|
||||
),
|
||||
})
|
||||
}
|
||||
pub(crate) fn enforce_integer_div(
|
||||
cs: &mut CS,
|
||||
left: ConstrainedInteger,
|
||||
right: ConstrainedInteger,
|
||||
) -> ConstrainedValue<F> {
|
||||
ConstrainedValue::Integer(match (left, right) {
|
||||
(ConstrainedInteger::U8(left_u8), ConstrainedInteger::U8(right_u8)) => {
|
||||
ConstrainedInteger::U8(Self::enforce_u8_div(cs, left_u8, right_u8))
|
||||
}
|
||||
(ConstrainedInteger::U32(left_u32), ConstrainedInteger::U32(right_u32)) => {
|
||||
ConstrainedInteger::U32(Self::enforce_u32_div(cs, left_u32, right_u32))
|
||||
}
|
||||
(left, right) => unimplemented!(
|
||||
"cannot enforce integer division between {} / {}",
|
||||
left,
|
||||
right
|
||||
),
|
||||
})
|
||||
}
|
||||
pub(crate) fn enforce_integer_pow(
|
||||
cs: &mut CS,
|
||||
left: ConstrainedInteger,
|
||||
right: ConstrainedInteger,
|
||||
) -> ConstrainedValue<F> {
|
||||
ConstrainedValue::Integer(match (left, right) {
|
||||
(ConstrainedInteger::U8(left_u8), ConstrainedInteger::U8(right_u8)) => {
|
||||
ConstrainedInteger::U8(Self::enforce_u8_pow(cs, left_u8, right_u8))
|
||||
}
|
||||
(ConstrainedInteger::U32(left_u32), ConstrainedInteger::U32(right_u32)) => {
|
||||
ConstrainedInteger::U32(Self::enforce_u32_pow(cs, left_u32, right_u32))
|
||||
}
|
||||
(left, right) => unimplemented!(
|
||||
"cannot enforce integer exponentiation between {} ** {}",
|
||||
left,
|
||||
right
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
10
compiler/src/constraints/integer/mod.rs
Normal file
10
compiler/src/constraints/integer/mod.rs
Normal file
@ -0,0 +1,10 @@
|
||||
//! Module containing methods to enforce constraints on integers in a Leo program
|
||||
|
||||
pub mod integer;
|
||||
pub use integer::*;
|
||||
|
||||
pub mod uint8;
|
||||
pub use uint8::*;
|
||||
|
||||
pub mod uint32;
|
||||
pub use uint32::*;
|
@ -1,8 +1,9 @@
|
||||
//! Methods to enforce constraints on integers in a resolved Leo program.
|
||||
//! Methods to enforce constraints on uint32s in a resolved Leo program.
|
||||
|
||||
use crate::{
|
||||
constraints::{new_variable_from_variable, ResolvedProgram, ResolvedValue},
|
||||
types::{Integer, ParameterModel, ParameterValue, Variable},
|
||||
constraints::{new_variable_from_variable, ConstrainedProgram, ConstrainedValue},
|
||||
types::{ParameterModel, ParameterValue, Variable},
|
||||
ConstrainedInteger,
|
||||
};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
@ -10,11 +11,11 @@ use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{
|
||||
r1cs::ConstraintSystem,
|
||||
utilities::{alloc::AllocGadget, boolean::Boolean, eq::EqGadget, uint32::UInt32},
|
||||
utilities::{alloc::AllocGadget, eq::EqGadget, uint32::UInt32},
|
||||
},
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
|
||||
pub(crate) fn u32_from_parameter(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
@ -45,7 +46,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
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(integer));
|
||||
self.store_variable(
|
||||
parameter_variable.clone(),
|
||||
ConstrainedValue::Integer(ConstrainedInteger::U32(integer)),
|
||||
);
|
||||
|
||||
parameter_variable
|
||||
}
|
||||
@ -80,72 +84,52 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
// parameter_variable
|
||||
}
|
||||
|
||||
pub(crate) fn get_integer_constant(integer: Integer) -> ResolvedValue<F> {
|
||||
match integer {
|
||||
Integer::U32(u32_value) => ResolvedValue::U32(UInt32::constant(u32_value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn u32_eq(left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||
ResolvedValue::Boolean(Boolean::Constant(left.eq(&right)))
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_u32_eq(cs: &mut CS, left: UInt32, right: UInt32) {
|
||||
left.enforce_equal(cs.ns(|| format!("enforce u32 equal")), &right)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_u32_add(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||
ResolvedValue::U32(
|
||||
UInt32::addmany(
|
||||
cs.ns(|| format!("enforce {} + {}", left.value.unwrap(), right.value.unwrap())),
|
||||
&[left, right],
|
||||
)
|
||||
.unwrap(),
|
||||
pub(crate) fn enforce_u32_add(cs: &mut CS, left: UInt32, right: UInt32) -> UInt32 {
|
||||
UInt32::addmany(
|
||||
cs.ns(|| format!("enforce {} + {}", left.value.unwrap(), right.value.unwrap())),
|
||||
&[left, right],
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_u32_sub(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||
ResolvedValue::U32(
|
||||
left.sub(
|
||||
cs.ns(|| format!("enforce {} - {}", left.value.unwrap(), right.value.unwrap())),
|
||||
&right,
|
||||
)
|
||||
.unwrap(),
|
||||
pub(crate) fn enforce_u32_sub(cs: &mut CS, left: UInt32, right: UInt32) -> UInt32 {
|
||||
left.sub(
|
||||
cs.ns(|| format!("enforce {} - {}", left.value.unwrap(), right.value.unwrap())),
|
||||
&right,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_u32_mul(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||
ResolvedValue::U32(
|
||||
left.mul(
|
||||
cs.ns(|| format!("enforce {} * {}", left.value.unwrap(), right.value.unwrap())),
|
||||
&right,
|
||||
)
|
||||
.unwrap(),
|
||||
pub(crate) fn enforce_u32_mul(cs: &mut CS, left: UInt32, right: UInt32) -> UInt32 {
|
||||
left.mul(
|
||||
cs.ns(|| format!("enforce {} * {}", left.value.unwrap(), right.value.unwrap())),
|
||||
&right,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
pub(crate) fn enforce_u32_div(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||
ResolvedValue::U32(
|
||||
left.div(
|
||||
cs.ns(|| format!("enforce {} / {}", left.value.unwrap(), right.value.unwrap())),
|
||||
&right,
|
||||
)
|
||||
.unwrap(),
|
||||
pub(crate) fn enforce_u32_div(cs: &mut CS, left: UInt32, right: UInt32) -> UInt32 {
|
||||
left.div(
|
||||
cs.ns(|| format!("enforce {} / {}", left.value.unwrap(), right.value.unwrap())),
|
||||
&right,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
pub(crate) fn enforce_u32_pow(cs: &mut CS, left: UInt32, right: UInt32) -> ResolvedValue<F> {
|
||||
ResolvedValue::U32(
|
||||
left.pow(
|
||||
cs.ns(|| {
|
||||
format!(
|
||||
"enforce {} ** {}",
|
||||
left.value.unwrap(),
|
||||
right.value.unwrap()
|
||||
)
|
||||
}),
|
||||
&right,
|
||||
)
|
||||
.unwrap(),
|
||||
pub(crate) fn enforce_u32_pow(cs: &mut CS, left: UInt32, right: UInt32) -> UInt32 {
|
||||
left.pow(
|
||||
cs.ns(|| {
|
||||
format!(
|
||||
"enforce {} ** {}",
|
||||
left.value.unwrap(),
|
||||
right.value.unwrap()
|
||||
)
|
||||
}),
|
||||
&right,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
135
compiler/src/constraints/integer/uint8.rs
Normal file
135
compiler/src/constraints/integer/uint8.rs
Normal file
@ -0,0 +1,135 @@
|
||||
//! Methods to enforce constraints on uint8s in a resolved Leo program.
|
||||
|
||||
use crate::{
|
||||
constraints::{new_variable_from_variable, ConstrainedProgram, ConstrainedValue},
|
||||
types::{ParameterModel, ParameterValue, Variable},
|
||||
ConstrainedInteger,
|
||||
};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{
|
||||
r1cs::ConstraintSystem,
|
||||
utilities::{alloc::AllocGadget, eq::EqGadget, uint8::UInt8},
|
||||
},
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
|
||||
pub(crate) fn u8_from_parameter(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
scope: String,
|
||||
parameter_model: ParameterModel<F>,
|
||||
parameter_value: Option<ParameterValue<F>>,
|
||||
) -> Variable<F> {
|
||||
// Check that the parameter value is the correct type
|
||||
let integer_option = parameter_value.map(|parameter| match parameter {
|
||||
ParameterValue::Integer(i) => i as u8,
|
||||
value => unimplemented!("expected integer parameter, got {}", value),
|
||||
});
|
||||
|
||||
// Check visibility of parameter
|
||||
let name = parameter_model.variable.name.clone();
|
||||
let integer = if parameter_model.private {
|
||||
UInt8::alloc(cs.ns(|| name), || {
|
||||
integer_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.unwrap()
|
||||
} else {
|
||||
UInt8::alloc_input(cs.ns(|| name), || {
|
||||
integer_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
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(),
|
||||
ConstrainedValue::Integer(ConstrainedInteger::U8(integer)),
|
||||
);
|
||||
|
||||
parameter_variable
|
||||
}
|
||||
|
||||
pub(crate) fn u8_array_from_parameter(
|
||||
&mut self,
|
||||
_cs: &mut CS,
|
||||
_scope: String,
|
||||
_parameter_model: ParameterModel<F>,
|
||||
_parameter_value: Option<ParameterValue<F>>,
|
||||
) -> Variable<F> {
|
||||
unimplemented!("Cannot enforce integer array as parameter")
|
||||
// // 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 {
|
||||
// UInt32::alloc(cs.ns(|| name), Some(argument)).unwrap()
|
||||
// } else {
|
||||
// UInt32::alloc_input(cs.ns(|| name), Some(argument)).unwrap()
|
||||
// };
|
||||
//
|
||||
// array_value.push(number);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// let parameter_variable = new_variable_from_variable(scope, ¶meter.variable);
|
||||
//
|
||||
// // store array as variable in resolved program
|
||||
// self.store_variable(parameter_variable.clone(), ResolvedValue::U32Array(array_value));
|
||||
//
|
||||
// parameter_variable
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_u8_eq(cs: &mut CS, left: UInt8, right: UInt8) {
|
||||
left.enforce_equal(cs.ns(|| format!("enforce u8 equal")), &right)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_u8_add(cs: &mut CS, left: UInt8, right: UInt8) -> UInt8 {
|
||||
UInt8::addmany(
|
||||
cs.ns(|| format!("enforce {} + {}", left.value.unwrap(), right.value.unwrap())),
|
||||
&[left, right],
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_u8_sub(cs: &mut CS, left: UInt8, right: UInt8) -> UInt8 {
|
||||
left.sub(
|
||||
cs.ns(|| format!("enforce {} - {}", left.value.unwrap(), right.value.unwrap())),
|
||||
&right,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_u8_mul(cs: &mut CS, left: UInt8, right: UInt8) -> UInt8 {
|
||||
left.mul(
|
||||
cs.ns(|| format!("enforce {} * {}", left.value.unwrap(), right.value.unwrap())),
|
||||
&right,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
pub(crate) fn enforce_u8_div(cs: &mut CS, left: UInt8, right: UInt8) -> UInt8 {
|
||||
left.div(
|
||||
cs.ns(|| format!("enforce {} / {}", left.value.unwrap(), right.value.unwrap())),
|
||||
&right,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
pub(crate) fn enforce_u8_pow(cs: &mut CS, left: UInt8, right: UInt8) -> UInt8 {
|
||||
left.pow(
|
||||
cs.ns(|| {
|
||||
format!(
|
||||
"enforce {} ** {}",
|
||||
left.value.unwrap(),
|
||||
right.value.unwrap()
|
||||
)
|
||||
}),
|
||||
&right,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
@ -4,8 +4,8 @@
|
||||
use crate::{
|
||||
ast,
|
||||
constraints::{
|
||||
new_scope, new_scope_from_variable, new_variable_from_variables, ResolvedProgram,
|
||||
ResolvedValue,
|
||||
new_scope, new_scope_from_variable, new_variable_from_variables, ConstrainedProgram,
|
||||
ConstrainedValue,
|
||||
},
|
||||
types::{Expression, Function, ParameterValue, Program, Type},
|
||||
Import,
|
||||
@ -19,7 +19,7 @@ use snarkos_models::{
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
|
||||
fn enforce_argument(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
@ -27,7 +27,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
caller_scope: String,
|
||||
function_name: String,
|
||||
argument: Expression<F>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<F> {
|
||||
match argument {
|
||||
Expression::Variable(variable) => self.enforce_variable(caller_scope, variable),
|
||||
expression => self.enforce_expression(cs, scope, function_name, expression),
|
||||
@ -41,7 +41,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
caller_scope: String,
|
||||
function: Function<F>,
|
||||
arguments: Vec<Expression<F>>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<F> {
|
||||
let function_name = new_scope(scope.clone(), function.get_name());
|
||||
|
||||
// Make sure we are given the correct number of arguments
|
||||
@ -62,7 +62,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
.for_each(|(parameter, argument)| {
|
||||
// Check that argument is correct type
|
||||
match parameter._type.clone() {
|
||||
Type::U32 => {
|
||||
Type::IntegerType(integer_type) => {
|
||||
match self.enforce_argument(
|
||||
cs,
|
||||
scope.clone(),
|
||||
@ -70,13 +70,14 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function_name.clone(),
|
||||
argument,
|
||||
) {
|
||||
ResolvedValue::U32(number) => {
|
||||
ConstrainedValue::Integer(number) => {
|
||||
number.expect_type(&integer_type);
|
||||
// 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::U32(number));
|
||||
self.store(variable_name, ConstrainedValue::Integer(number));
|
||||
}
|
||||
argument => {
|
||||
unimplemented!("expected integer argument got {}", argument)
|
||||
@ -91,13 +92,13 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function_name.clone(),
|
||||
argument,
|
||||
) {
|
||||
ResolvedValue::FieldElement(fe) => {
|
||||
ConstrainedValue::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(fe));
|
||||
self.store(variable_name, ConstrainedValue::FieldElement(fe));
|
||||
}
|
||||
argument => unimplemented!("expected field argument got {}", argument),
|
||||
}
|
||||
@ -110,13 +111,13 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function_name.clone(),
|
||||
argument,
|
||||
) {
|
||||
ResolvedValue::Boolean(bool) => {
|
||||
ConstrainedValue::Boolean(bool) => {
|
||||
// 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::Boolean(bool));
|
||||
self.store(variable_name, ConstrainedValue::Boolean(bool));
|
||||
}
|
||||
argument => {
|
||||
unimplemented!("expected boolean argument got {}", argument)
|
||||
@ -129,7 +130,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|
||||
// Evaluate function statements
|
||||
|
||||
let mut return_values = ResolvedValue::Return(vec![]);
|
||||
let mut return_values = ConstrainedValue::Return(vec![]);
|
||||
|
||||
for statement in function.statements.iter() {
|
||||
if let Some(returned) = self.enforce_statement(
|
||||
@ -153,7 +154,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
scope: String,
|
||||
function: Function<F>,
|
||||
parameters: Vec<Option<ParameterValue<F>>>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<F> {
|
||||
let function_name = new_scope(scope.clone(), function.get_name());
|
||||
let mut arguments = vec![];
|
||||
|
||||
@ -168,7 +169,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
.for_each(|(parameter_model, parameter_value)| {
|
||||
// append each variable to arguments vector
|
||||
arguments.push(Expression::Variable(match parameter_model._type {
|
||||
Type::U32 => self.u32_from_parameter(
|
||||
Type::IntegerType(ref _integer_type) => self.integer_from_parameter(
|
||||
cs,
|
||||
function_name.clone(),
|
||||
parameter_model,
|
||||
@ -187,7 +188,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
parameter_value,
|
||||
),
|
||||
Type::Array(ref ty, _length) => match *ty.clone() {
|
||||
Type::U32 => self.u32_array_from_parameter(
|
||||
Type::IntegerType(_type) => self.integer_array_from_parameter(
|
||||
cs,
|
||||
function_name.clone(),
|
||||
parameter_model,
|
||||
@ -259,7 +260,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
// store imported struct under resolved name
|
||||
self.store_variable(
|
||||
resolved_struct_name,
|
||||
ResolvedValue::StructDefinition(struct_def),
|
||||
ConstrainedValue::StructDefinition(struct_def),
|
||||
);
|
||||
}
|
||||
None => {
|
||||
@ -280,7 +281,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
// store imported function under resolved name
|
||||
self.store_variable(
|
||||
resolved_function_name,
|
||||
ResolvedValue::Function(function),
|
||||
ConstrainedValue::Function(function),
|
||||
)
|
||||
}
|
||||
None => unimplemented!(
|
||||
@ -318,7 +319,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
new_variable_from_variables(&program_name.clone(), &variable);
|
||||
self.store_variable(
|
||||
resolved_struct_name,
|
||||
ResolvedValue::StructDefinition(struct_def),
|
||||
ConstrainedValue::StructDefinition(struct_def),
|
||||
);
|
||||
});
|
||||
|
||||
@ -328,7 +329,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
.into_iter()
|
||||
.for_each(|(function_name, function)| {
|
||||
let resolved_function_name = new_scope(program_name.name.clone(), function_name.0);
|
||||
self.store(resolved_function_name, ResolvedValue::Function(function));
|
||||
self.store(resolved_function_name, ConstrainedValue::Function(function));
|
||||
});
|
||||
}
|
||||
|
||||
@ -336,8 +337,8 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
cs: &mut CS,
|
||||
program: Program<F>,
|
||||
parameters: Vec<Option<ParameterValue<F>>>,
|
||||
) -> ResolvedValue<F> {
|
||||
let mut resolved_program = ResolvedProgram::new();
|
||||
) -> ConstrainedValue<F> {
|
||||
let mut resolved_program = ConstrainedProgram::new();
|
||||
let program_name = program.get_name();
|
||||
let main_function_name = new_scope(program_name.clone(), "main".into());
|
||||
|
||||
@ -348,7 +349,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
.expect("main function not defined");
|
||||
|
||||
match main.clone() {
|
||||
ResolvedValue::Function(function) => {
|
||||
ConstrainedValue::Function(function) => {
|
||||
let result =
|
||||
resolved_program.enforce_main_function(cs, program_name, function, parameters);
|
||||
log::debug!("{}", result);
|
||||
|
@ -15,11 +15,11 @@ pub use integer::*;
|
||||
pub mod field_element;
|
||||
pub use field_element::*;
|
||||
|
||||
pub mod resolved_program;
|
||||
pub use resolved_program::*;
|
||||
pub mod constrained_program;
|
||||
pub use constrained_program::*;
|
||||
|
||||
pub mod resolved_value;
|
||||
pub use resolved_value::*;
|
||||
pub mod constrained_value;
|
||||
pub use constrained_value::*;
|
||||
|
||||
pub mod statement;
|
||||
pub use statement::*;
|
||||
|
@ -1,11 +1,12 @@
|
||||
//! Methods to enforce constraints on statements in a resolved Leo program.
|
||||
|
||||
use crate::{
|
||||
constraints::{new_scope_from_variable, ResolvedProgram, ResolvedValue},
|
||||
constraints::{new_scope_from_variable, ConstrainedProgram, ConstrainedValue},
|
||||
types::{
|
||||
Assignee, ConditionalNestedOrEnd, ConditionalStatement, Expression, Integer,
|
||||
RangeOrExpression, Statement, Type, Variable,
|
||||
},
|
||||
ConstrainedInteger,
|
||||
};
|
||||
|
||||
use snarkos_models::{
|
||||
@ -13,7 +14,7 @@ use snarkos_models::{
|
||||
gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean, utilities::uint32::UInt32},
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ConstrainedProgram<F, CS> {
|
||||
fn resolve_assignee(&mut self, scope: String, assignee: Assignee<F>) -> String {
|
||||
match assignee {
|
||||
Assignee::Variable(name) => new_scope_from_variable(scope, &name),
|
||||
@ -30,7 +31,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
assignee: Assignee<F>,
|
||||
return_value: &mut ResolvedValue<F>,
|
||||
return_value: &mut ConstrainedValue<F>,
|
||||
) {
|
||||
match assignee {
|
||||
Assignee::Variable(name) => {
|
||||
@ -56,7 +57,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
// Modify the single value of the array in place
|
||||
match self.get_mut(&expected_array_name) {
|
||||
Some(value) => match value {
|
||||
ResolvedValue::Array(old) => {
|
||||
ConstrainedValue::Array(old) => {
|
||||
old[index] = return_value.to_owned();
|
||||
}
|
||||
_ => {
|
||||
@ -82,7 +83,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
// Modify the range of values of the array in place
|
||||
match self.get_mut(&expected_array_name) {
|
||||
Some(value) => match (value, return_value) {
|
||||
(ResolvedValue::Array(old), ResolvedValue::Array(new)) => {
|
||||
(ConstrainedValue::Array(old), ConstrainedValue::Array(new)) => {
|
||||
let to_index = to_index_option.unwrap_or(old.len());
|
||||
old.splice(from_index..to_index, new.iter().cloned());
|
||||
}
|
||||
@ -105,7 +106,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
|
||||
match self.get_mut(&expected_struct_name) {
|
||||
Some(value) => match value {
|
||||
ResolvedValue::StructExpression(_variable, members) => {
|
||||
ConstrainedValue::StructExpression(_variable, members) => {
|
||||
// Modify the struct member in place
|
||||
let matched_member =
|
||||
members.into_iter().find(|member| member.0 == struct_member);
|
||||
@ -176,11 +177,8 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
match ty {
|
||||
// Explicit type
|
||||
Some(ty) => {
|
||||
if result_value.match_type(&ty) {
|
||||
self.store_assignment(cs, file_scope, function_scope, assignee, result_value);
|
||||
} else {
|
||||
unimplemented!("incompatible types {} = {}", assignee, result_value)
|
||||
}
|
||||
result_value.expect_type(&ty);
|
||||
self.store_assignment(cs, file_scope, function_scope, assignee, result_value);
|
||||
}
|
||||
// Implicit type
|
||||
None => self.store_assignment(cs, file_scope, function_scope, assignee, result_value),
|
||||
@ -199,7 +197,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
let return_values =
|
||||
match self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), function)
|
||||
{
|
||||
ResolvedValue::Return(values) => values,
|
||||
ConstrainedValue::Return(values) => values,
|
||||
value => unimplemented!(
|
||||
"multiple assignment only implemented for functions, got {}",
|
||||
value
|
||||
@ -227,7 +225,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function_scope: String,
|
||||
expressions: Vec<Expression<F>>,
|
||||
return_types: Vec<Type<F>>,
|
||||
) -> ResolvedValue<F> {
|
||||
) -> ConstrainedValue<F> {
|
||||
// Make sure we return the correct number of values
|
||||
if return_types.len() != expressions.len() {
|
||||
unimplemented!(
|
||||
@ -237,7 +235,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
)
|
||||
}
|
||||
|
||||
ResolvedValue::Return(
|
||||
ConstrainedValue::Return(
|
||||
expressions
|
||||
.into_iter()
|
||||
.zip(return_types.into_iter())
|
||||
@ -248,13 +246,10 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function_scope.clone(),
|
||||
expression,
|
||||
);
|
||||
if !result.match_type(&ty) {
|
||||
unimplemented!("expected return type {}, got {}", ty, result)
|
||||
} else {
|
||||
result
|
||||
}
|
||||
result.expect_type(&ty);
|
||||
result
|
||||
})
|
||||
.collect::<Vec<ResolvedValue<F>>>(),
|
||||
.collect::<Vec<ConstrainedValue<F>>>(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -265,7 +260,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function_scope: String,
|
||||
statements: Vec<Statement<F>>,
|
||||
return_types: Vec<Type<F>>,
|
||||
) -> Option<ResolvedValue<F>> {
|
||||
) -> Option<ConstrainedValue<F>> {
|
||||
let mut res = None;
|
||||
// Evaluate statements and possibly return early
|
||||
for statement in statements.iter() {
|
||||
@ -291,14 +286,14 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function_scope: String,
|
||||
statement: ConditionalStatement<F>,
|
||||
return_types: Vec<Type<F>>,
|
||||
) -> Option<ResolvedValue<F>> {
|
||||
) -> Option<ConstrainedValue<F>> {
|
||||
let condition = match self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
statement.condition.clone(),
|
||||
) {
|
||||
ResolvedValue::Boolean(resolved) => resolved,
|
||||
ConstrainedValue::Boolean(resolved) => resolved,
|
||||
value => unimplemented!("if else conditional must resolve to boolean, got {}", value),
|
||||
};
|
||||
|
||||
@ -344,14 +339,17 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
stop: Integer,
|
||||
statements: Vec<Statement<F>>,
|
||||
return_types: Vec<Type<F>>,
|
||||
) -> Option<ResolvedValue<F>> {
|
||||
) -> Option<ConstrainedValue<F>> {
|
||||
let mut res = None;
|
||||
|
||||
for i in start.to_usize()..stop.to_usize() {
|
||||
// Store index in current function scope.
|
||||
// For loop scope is not implemented.
|
||||
let index_name = new_scope_from_variable(function_scope.clone(), &index);
|
||||
self.store(index_name, ResolvedValue::U32(UInt32::constant(i as u32)));
|
||||
self.store(
|
||||
index_name,
|
||||
ConstrainedValue::Integer(ConstrainedInteger::U32(UInt32::constant(i as u32))),
|
||||
);
|
||||
|
||||
// Evaluate statements and possibly return early
|
||||
if let Some(early_return) = self.iterate_or_early_return(
|
||||
@ -372,17 +370,17 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
fn enforce_assert_eq_statement(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
left: ResolvedValue<F>,
|
||||
right: ResolvedValue<F>,
|
||||
left: ConstrainedValue<F>,
|
||||
right: ConstrainedValue<F>,
|
||||
) {
|
||||
match (left, right) {
|
||||
(ResolvedValue::Boolean(bool_1), ResolvedValue::Boolean(bool_2)) => {
|
||||
(ConstrainedValue::Boolean(bool_1), ConstrainedValue::Boolean(bool_2)) => {
|
||||
self.enforce_boolean_eq(cs, bool_1, bool_2)
|
||||
}
|
||||
(ResolvedValue::U32(num_1), ResolvedValue::U32(num_2)) => {
|
||||
Self::enforce_u32_eq(cs, num_1, num_2)
|
||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||
Self::enforce_integer_eq(cs, num_1, num_2)
|
||||
}
|
||||
(ResolvedValue::FieldElement(fe_1), ResolvedValue::FieldElement(fe_2)) => {
|
||||
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
|
||||
self.enforce_field_eq(cs, fe_1, fe_2)
|
||||
}
|
||||
(val_1, val_2) => {
|
||||
@ -398,7 +396,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
function_scope: String,
|
||||
statement: Statement<F>,
|
||||
return_types: Vec<Type<F>>,
|
||||
) -> Option<ResolvedValue<F>> {
|
||||
) -> Option<ConstrainedValue<F>> {
|
||||
let mut res = None;
|
||||
match statement {
|
||||
Statement::Return(expressions) => {
|
||||
@ -467,7 +465,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
|
||||
}
|
||||
Statement::Expression(expression) => {
|
||||
match self.enforce_expression(cs, file_scope, function_scope, expression.clone()) {
|
||||
ResolvedValue::Return(values) => {
|
||||
ConstrainedValue::Return(values) => {
|
||||
if !values.is_empty() {
|
||||
unimplemented!("function return values not assigned {:#?}", values)
|
||||
}
|
||||
|
@ -56,11 +56,16 @@ operation_assign = {
|
||||
}
|
||||
|
||||
/// types
|
||||
|
||||
type_u8 = {"u8"}
|
||||
type_u32 = {"u32"}
|
||||
type_integer = {
|
||||
type_u8
|
||||
| type_u32
|
||||
}
|
||||
|
||||
type_field = {"fe"}
|
||||
type_bool = {"bool"}
|
||||
type_basic = { type_u32 | type_field | type_bool }
|
||||
type_basic = { type_integer | type_field | type_bool }
|
||||
type_struct = { variable }
|
||||
type_basic_or_struct = {type_basic | type_struct }
|
||||
type_array = {type_basic ~ ("[" ~ value ~ "]")+ }
|
||||
@ -70,10 +75,10 @@ type_list = _{(_type ~ ("," ~ _type)*)?}
|
||||
/// Values
|
||||
|
||||
value_number = @{ "0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* }
|
||||
value_u32 = { value_number ~ type_u32? }
|
||||
value_integer = { value_number ~ type_integer? }
|
||||
value_field = { value_number ~ type_field }
|
||||
value_boolean = { "true" | "false" }
|
||||
value = { value_field | value_boolean | value_u32 }
|
||||
value = { value_field | value_boolean | value_integer }
|
||||
|
||||
/// Variables
|
||||
|
||||
|
@ -17,7 +17,7 @@ pub struct Variable<F: Field + PrimeField> {
|
||||
/// An integer type enum wrapping the integer value
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Integer {
|
||||
// U8(u8),
|
||||
U8(u8),
|
||||
U32(u32),
|
||||
// U64(u64),
|
||||
}
|
||||
@ -25,7 +25,7 @@ pub enum Integer {
|
||||
impl Integer {
|
||||
pub fn to_usize(&self) -> usize {
|
||||
match *self {
|
||||
// U8(u8)
|
||||
Integer::U8(num) => num as usize,
|
||||
Integer::U32(num) => num as usize,
|
||||
// U64(u64)
|
||||
}
|
||||
@ -97,10 +97,17 @@ pub enum Assignee<F: Field + PrimeField> {
|
||||
StructMember(Box<Assignee<F>>, Variable<F>),
|
||||
}
|
||||
|
||||
/// Explicit integer type
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum IntegerType {
|
||||
U8,
|
||||
U32,
|
||||
}
|
||||
|
||||
/// Explicit type used for defining a variable or expression type
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Type<F: Field + PrimeField> {
|
||||
U32,
|
||||
IntegerType(IntegerType),
|
||||
FieldElement,
|
||||
Boolean,
|
||||
Array(Box<Type<F>>, usize),
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
use crate::{
|
||||
Assignee, ConditionalNestedOrEnd, ConditionalStatement, Expression, Function, FunctionName,
|
||||
Integer, ParameterModel, ParameterValue, RangeOrExpression, SpreadOrExpression, Statement,
|
||||
Struct, StructField, Type, Variable,
|
||||
Integer, IntegerType, ParameterModel, ParameterValue, RangeOrExpression, SpreadOrExpression,
|
||||
Statement, Struct, StructField, Type, Variable,
|
||||
};
|
||||
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
@ -23,6 +23,7 @@ impl<F: Field + PrimeField> fmt::Debug for Variable<F> {
|
||||
impl fmt::Display for Integer {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Integer::U8(ref num) => write!(f, "{}", num),
|
||||
Integer::U32(ref num) => write!(f, "{}", num),
|
||||
}
|
||||
}
|
||||
@ -217,10 +218,19 @@ impl<F: Field + PrimeField> fmt::Display for Statement<F> {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for IntegerType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
IntegerType::U8 => write!(f, "u8"),
|
||||
IntegerType::U32 => write!(f, "u32"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> fmt::Display for Type<F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Type::U32 => write!(f, "u32"),
|
||||
Type::IntegerType(ref integer_type) => write!(f, "{}", integer_type),
|
||||
Type::FieldElement => write!(f, "fe"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::Struct(ref variable) => write!(f, "{}", variable),
|
||||
|
@ -23,15 +23,32 @@ impl<'ast, F: Field + PrimeField> From<ast::Variable<'ast>> for types::Expressio
|
||||
}
|
||||
/// pest ast - types::Integer
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::U32<'ast>> for types::Expression<F> {
|
||||
fn from(field: ast::U32<'ast>) -> Self {
|
||||
types::Expression::Integer(types::Integer::U32(
|
||||
field
|
||||
.number
|
||||
.value
|
||||
.parse::<u32>()
|
||||
.expect("unable to parse u32"),
|
||||
))
|
||||
impl<'ast> types::Integer {
|
||||
pub(crate) fn from(number: ast::Number<'ast>, _type: ast::IntegerType) -> Self {
|
||||
match _type {
|
||||
ast::IntegerType::U8Type(_u8) => {
|
||||
types::Integer::U8(number.value.parse::<u8>().expect("unable to parse u8"))
|
||||
}
|
||||
ast::IntegerType::U32Type(_u32) => {
|
||||
types::Integer::U32(number.value.parse::<u32>().expect("unable to parse u32"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::Integer<'ast>> for types::Expression<F> {
|
||||
fn from(field: ast::Integer<'ast>) -> Self {
|
||||
types::Expression::Integer(match field._type {
|
||||
Some(_type) => types::Integer::from(field.number, _type),
|
||||
// default integer type is u32
|
||||
None => types::Integer::U32(
|
||||
field
|
||||
.number
|
||||
.value
|
||||
.parse::<u32>()
|
||||
.expect("unable to parse u32"),
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +108,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Boolean<'ast>> for types::Expression
|
||||
impl<'ast, F: Field + PrimeField> From<ast::Value<'ast>> for types::Expression<F> {
|
||||
fn from(value: ast::Value<'ast>) -> Self {
|
||||
match value {
|
||||
ast::Value::U32(num) => types::Expression::from(num),
|
||||
ast::Value::Integer(num) => types::Expression::from(num),
|
||||
ast::Value::Field(fe) => types::Expression::from(fe),
|
||||
ast::Value::Boolean(bool) => types::Expression::from(bool),
|
||||
}
|
||||
@ -290,7 +307,7 @@ impl<'ast, F: Field + PrimeField> From<ast::Expression<'ast>> for types::Express
|
||||
impl<'ast, F: Field + PrimeField> types::Expression<F> {
|
||||
fn get_count(count: ast::Value<'ast>) -> usize {
|
||||
match count {
|
||||
ast::Value::U32(f) => f
|
||||
ast::Value::Integer(f) => f
|
||||
.number
|
||||
.value
|
||||
.parse::<usize>()
|
||||
@ -554,10 +571,19 @@ impl<'ast, F: Field + PrimeField> From<ast::Statement<'ast>> for types::Statemen
|
||||
|
||||
/// pest ast -> Explicit types::Type for defining struct members and function params
|
||||
|
||||
impl From<ast::IntegerType> for types::IntegerType {
|
||||
fn from(integer_type: ast::IntegerType) -> Self {
|
||||
match integer_type {
|
||||
ast::IntegerType::U8Type(_type) => types::IntegerType::U8,
|
||||
ast::IntegerType::U32Type(_type) => types::IntegerType::U32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, F: Field + PrimeField> From<ast::BasicType<'ast>> for types::Type<F> {
|
||||
fn from(basic_type: ast::BasicType<'ast>) -> Self {
|
||||
match basic_type {
|
||||
ast::BasicType::U32(_ty) => types::Type::U32,
|
||||
ast::BasicType::Integer(ty) => types::Type::IntegerType(types::IntegerType::from(ty)),
|
||||
ast::BasicType::Field(_ty) => types::Type::FieldElement,
|
||||
ast::BasicType::Boolean(_ty) => types::Type::Boolean,
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use leo_compiler::{compiler::Compiler, ResolvedValue};
|
||||
use leo_compiler::{compiler::Compiler, ConstrainedValue};
|
||||
|
||||
use snarkos_curves::bls12_377::Fr;
|
||||
|
||||
@ -39,7 +39,7 @@ fn test_zero() {
|
||||
|
||||
let output = output.unwrap();
|
||||
assert_eq!(
|
||||
ResolvedValue::<Fr>::Return(vec![ResolvedValue::<Fr>::U32(UInt32::constant(0))]),
|
||||
ConstrainedValue::<Fr>::Return(vec![ConstrainedValue::<Fr>::Integer(UInt32::constant(0))]),
|
||||
output
|
||||
);
|
||||
println!("{}", output);
|
||||
@ -54,7 +54,7 @@ fn test_one() {
|
||||
|
||||
let output = output.unwrap();
|
||||
assert_eq!(
|
||||
ResolvedValue::<Fr>::Return(vec![ResolvedValue::<Fr>::U32(UInt32::constant(1))]),
|
||||
ConstrainedValue::<Fr>::Return(vec![ConstrainedValue::<Fr>::Integer(UInt32::constant(1))]),
|
||||
output
|
||||
);
|
||||
println!("{}", output);
|
||||
@ -69,7 +69,7 @@ fn test_1_plus_1() {
|
||||
|
||||
let output = output.unwrap();
|
||||
assert_eq!(
|
||||
ResolvedValue::<Fr>::Return(vec![ResolvedValue::<Fr>::U32(UInt32::constant(2))]),
|
||||
ConstrainedValue::<Fr>::Return(vec![ConstrainedValue::<Fr>::Integer(UInt32::constant(2))]),
|
||||
output
|
||||
);
|
||||
println!("{}", output);
|
||||
@ -84,7 +84,7 @@ fn test_1_minus_1() {
|
||||
|
||||
let output = output.unwrap();
|
||||
assert_eq!(
|
||||
ResolvedValue::<Fr>::Return(vec![ResolvedValue::<Fr>::U32(UInt32::constant(0))]),
|
||||
ConstrainedValue::<Fr>::Return(vec![ConstrainedValue::<Fr>::Integer(UInt32::constant(0))]),
|
||||
output
|
||||
);
|
||||
println!("{}", output);
|
||||
|
Loading…
Reference in New Issue
Block a user