refactor integer module, add uint8 type

This commit is contained in:
collin 2020-05-06 17:22:00 -07:00
parent dcd484a62f
commit 73e431e9eb
21 changed files with 776 additions and 346 deletions

View File

@ -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);
}

View File

@ -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, &params, rng).unwrap();

View File

@ -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),
}

View File

@ -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

View File

@ -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, &parameter_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) {

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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"),
};

View File

@ -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))
}
}
}

View 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 &parameter_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, &parameter.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
),
})
}
}

View 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::*;

View File

@ -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, &parameter_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()
}
}

View 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, &parameter_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, &parameter.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()
}
}

View File

@ -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(),
&parameter.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(),
&parameter.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(),
&parameter.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);

View File

@ -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::*;

View File

@ -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)
}

View File

@ -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

View File

@ -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),

View File

@ -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),

View File

@ -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,
}

View File

@ -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);