Merge pull request #112 from AleoHQ/feature/signed-integer-syntax

Feature/signed integer syntax
This commit is contained in:
Howard Wu 2020-07-17 16:29:36 -07:00 committed by GitHub
commit 45e57cc0e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
331 changed files with 5004 additions and 1392 deletions

27
Cargo.lock generated
View File

@ -540,6 +540,7 @@ dependencies = [
"env_logger", "env_logger",
"from-pest", "from-pest",
"leo-compiler", "leo-compiler",
"leo-gadgets",
"leo-inputs", "leo-inputs",
"log", "log",
"rand", "rand",
@ -579,11 +580,14 @@ dependencies = [
"bincode", "bincode",
"hex", "hex",
"leo-ast", "leo-ast",
"leo-gadgets",
"leo-inputs", "leo-inputs",
"leo-types", "leo-types",
"log", "log",
"num-bigint",
"pest", "pest",
"rand", "rand",
"rand_xorshift",
"sha2", "sha2",
"snarkos-curves", "snarkos-curves",
"snarkos-dpc", "snarkos-dpc",
@ -595,6 +599,18 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "leo-gadgets"
version = "0.1.0"
dependencies = [
"rand",
"rand_xorshift",
"snarkos-errors",
"snarkos-models",
"snarkos-utilities",
"thiserror",
]
[[package]] [[package]]
name = "leo-inputs" name = "leo-inputs"
version = "0.1.0" version = "0.1.0"
@ -680,6 +696,17 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab250442c86f1850815b5d268639dff018c0627022bc1940eb2d642ca1ce12f0" checksum = "ab250442c86f1850815b5d268639dff018c0627022bc1940eb2d642ca1ce12f0"
[[package]]
name = "num-bigint"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7f3fc75e3697059fb1bc465e3d8cca6cf92f56854f201158b3f9c77d5a3cfa0"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.43" version = "0.1.43"

View File

@ -13,11 +13,12 @@ name = "leo"
path = "leo/main.rs" path = "leo/main.rs"
[workspace] [workspace]
members = [ "ast", "compiler", "leo-inputs", "types" ] members = [ "ast", "compiler", "gadgets", "leo-inputs", "types" ]
[dependencies] [dependencies]
leo-compiler = { path = "compiler", version = "0.1.0" } leo-compiler = { path = "compiler", version = "0.1.0" }
leo-inputs = { path = "leo-inputs", version = "0.1.0"} leo-gadgets = { path = "gadgets", version = "0.1.0" }
leo-inputs = { path = "leo-inputs", version = "0.1.0" }
snarkos-algorithms = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } snarkos-algorithms = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
snarkos-curves = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } snarkos-curves = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }

View File

@ -81,7 +81,7 @@ operation_gt = { ">" }
operation_le = { "<=" } operation_le = { "<=" }
operation_lt = { "<" } operation_lt = { "<" }
operation_add = { "+" } operation_add = { "+" }
operation_sub = { "-" } operation_sub = { "- " }
operation_mul = { "*" } operation_mul = { "*" }
operation_div = { "/" } operation_div = { "/" }
operation_pow = { "**" } operation_pow = { "**" }
@ -120,13 +120,27 @@ type_integer = {
| type_u32 | type_u32
| type_u64 | type_u64
| type_u128 | type_u128
| type_i8
| type_i16
| type_i32
| type_i64
| type_i128
} }
// Declared in types/integer.rs
type_u8 = { "u8" } type_u8 = { "u8" }
type_u16 = { "u16" } type_u16 = { "u16" }
type_u32 = { "u32" } type_u32 = { "u32" }
type_u64 = { "u64" } type_u64 = { "u64" }
type_u128 = { "u128" } type_u128 = { "u128" }
// Declared in types/integer.rs
type_i8 = { "i8" }
type_i16 = { "i16" }
type_i32 = { "i32" }
type_i64 = { "i64" }
type_i128 = { "i128" }
// Declared in types/field_type.rs // Declared in types/field_type.rs
type_field = { "field" } type_field = { "field" }
@ -172,7 +186,7 @@ value = {
} }
// Declared in values/number_value.rs // Declared in values/number_value.rs
value_number = @{ "0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* } value_number = @{ (("-" ~ ASCII_NONZERO_DIGIT) | "0" | ASCII_NONZERO_DIGIT) ~ ASCII_DIGIT* }
// Declared in values/number_implicit_value.rs // Declared in values/number_implicit_value.rs
value_implicit = { value_number } value_implicit = { value_number }

View File

@ -10,8 +10,16 @@ pub enum IntegerType {
U32Type(U32Type), U32Type(U32Type),
U64Type(U64Type), U64Type(U64Type),
U128Type(U128Type), U128Type(U128Type),
I8Type(I8Type),
I16Type(I16Type),
I32Type(I32Type),
I64Type(I64Type),
I128Type(I128Type),
} }
// Unsigned
#[derive(Clone, Debug, FromPest, PartialEq)] #[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_u8))] #[pest_ast(rule(Rule::type_u8))]
pub struct U8Type {} pub struct U8Type {}
@ -31,3 +39,25 @@ pub struct U64Type {}
#[derive(Clone, Debug, FromPest, PartialEq)] #[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_u128))] #[pest_ast(rule(Rule::type_u128))]
pub struct U128Type {} pub struct U128Type {}
// Signed
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_i8))]
pub struct I8Type {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_i16))]
pub struct I16Type {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_i32))]
pub struct I32Type {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_i64))]
pub struct I64Type {}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::type_i128))]
pub struct I128Type {}

View File

@ -6,8 +6,9 @@ edition = "2018"
[dependencies] [dependencies]
leo-ast = { path = "../ast", version = "0.1.0" } leo-ast = { path = "../ast", version = "0.1.0" }
leo-types = { path = "../types", version = "0.1.0" } leo-gadgets = { path = "../gadgets", version = "0.1.0" }
leo-inputs = { path = "../leo-inputs", version = "0.1.0" } leo-inputs = { path = "../leo-inputs", version = "0.1.0" }
leo-types = { path = "../types", version = "0.1.0" }
snarkos-curves = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } snarkos-curves = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
snarkos-dpc = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } snarkos-dpc = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
@ -15,14 +16,17 @@ snarkos-errors = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56
snarkos-gadgets = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } snarkos-gadgets = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
snarkos-objects = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } snarkos-objects = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false }
snarkos-utilities = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9" }
bincode = { version = "1.0" } bincode = { version = "1.0" }
hex = { version = "0.4.2" } hex = { version = "0.4.2" }
log = { version = "0.4" } log = { version = "0.4" }
pest = { version = "2.0" } pest = { version = "2.0" }
rand = { version = "0.7" } rand = { version = "0.7" }
rand_xorshift = { version = "0.2", default-features = false }
sha2 = { version = "0.9" } sha2 = { version = "0.9" }
thiserror = { version = "1.0" } thiserror = { version = "1.0" }
[dev-dependencies] [dev-dependencies]
snarkos-utilities = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9" } num-bigint = { version = "0.3" }

View File

@ -1,3 +1,4 @@
use leo_gadgets::errors::SignedIntegerError;
use leo_types::{error::Error as FormattedError, Span}; use leo_types::{error::Error as FormattedError, Span};
use snarkos_errors::gadgets::SynthesisError; use snarkos_errors::gadgets::SynthesisError;
@ -29,6 +30,27 @@ impl IntegerError {
Self::new_from_span(message, span) Self::new_from_span(message, span)
} }
pub fn signed(error: SignedIntegerError, span: Span) -> Self {
let message = format!("integer operation failed due to the signed integer error `{:?}`", error,);
Self::new_from_span(message, span)
}
pub fn synthesis(error: SynthesisError, span: Span) -> Self {
let message = format!("integer operation failed due to the synthesis error `{}`", error,);
Self::new_from_span(message, span)
}
pub fn signed_error(operation: String, error: SignedIntegerError, span: Span) -> Self {
let message = format!(
"the integer operation `{}` failed due to the signed integer error `{:?}`",
operation, error
);
Self::new_from_span(message, span)
}
pub fn cannot_evaluate(operation: String, span: Span) -> Self { pub fn cannot_evaluate(operation: String, span: Span) -> Self {
let message = format!( let message = format!(
"the integer binary operation `{}` can only be enforced on integers of the same type", "the integer binary operation `{}` can only be enforced on integers of the same type",
@ -46,7 +68,7 @@ impl IntegerError {
} }
pub fn invalid_integer(actual: String, span: Span) -> Self { pub fn invalid_integer(actual: String, span: Span) -> Self {
let message = format!("expected integer input type, found `{}`", actual); let message = format!("failed to parse `{}` as expected integer type", actual);
Self::new_from_span(message, span) Self::new_from_span(message, span)
} }

View File

@ -1,6 +1,7 @@
//! Enforces a relational `>=` operator in a resolved Leo program. //! Enforces a relational `>=` operator in a resolved Leo program.
use crate::{comparator::ComparatorGadget, errors::ExpressionError, value::ConstrainedValue, GroupType}; use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType};
use leo_gadgets::bits::ComparatorGadget;
use leo_types::Span; use leo_types::Span;
use snarkos_models::{ use snarkos_models::{
@ -19,9 +20,6 @@ pub fn evaluate_ge<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
num_1.greater_than_or_equal(unique_namespace, &num_2) num_1.greater_than_or_equal(unique_namespace, &num_2)
} }
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
field_1.greater_than_or_equal(unique_namespace, &field_2)
}
(ConstrainedValue::Unresolved(string), val_2) => { (ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
return evaluate_ge(&mut unique_namespace, val_1, val_2, span); return evaluate_ge(&mut unique_namespace, val_1, val_2, span);

View File

@ -1,6 +1,7 @@
//! Enforces a relational `>` operator in a resolved Leo program. //! Enforces a relational `>` operator in a resolved Leo program.
use crate::{comparator::ComparatorGadget, errors::ExpressionError, value::ConstrainedValue, GroupType}; use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType};
use leo_gadgets::bits::ComparatorGadget;
use leo_types::Span; use leo_types::Span;
use snarkos_models::{ use snarkos_models::{
@ -19,9 +20,6 @@ pub fn evaluate_gt<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
num_1.greater_than(unique_namespace, &num_2) num_1.greater_than(unique_namespace, &num_2)
} }
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
field_1.greater_than(unique_namespace, &field_2)
}
(ConstrainedValue::Unresolved(string), val_2) => { (ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
return evaluate_gt(&mut unique_namespace, val_1, val_2, span); return evaluate_gt(&mut unique_namespace, val_1, val_2, span);

View File

@ -1,6 +1,7 @@
//! Enforces a relational `<=` operator in a resolved Leo program. //! Enforces a relational `<=` operator in a resolved Leo program.
use crate::{comparator::ComparatorGadget, errors::ExpressionError, value::ConstrainedValue, GroupType}; use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType};
use leo_gadgets::bits::ComparatorGadget;
use leo_types::Span; use leo_types::Span;
use snarkos_models::{ use snarkos_models::{
@ -19,9 +20,6 @@ pub fn evaluate_le<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
num_1.less_than_or_equal(unique_namespace, &num_2) num_1.less_than_or_equal(unique_namespace, &num_2)
} }
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
field_1.less_than_or_equal(unique_namespace, &field_2)
}
(ConstrainedValue::Unresolved(string), val_2) => { (ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
return evaluate_le(&mut unique_namespace, val_1, val_2, span); return evaluate_le(&mut unique_namespace, val_1, val_2, span);

View File

@ -1,6 +1,7 @@
//! Enforces a relational `<` operator in a resolved Leo program. //! Enforces a relational `<` operator in a resolved Leo program.
use crate::{comparator::EvaluateLtGadget, errors::ExpressionError, value::ConstrainedValue, GroupType}; use crate::{errors::ExpressionError, value::ConstrainedValue, GroupType};
use leo_gadgets::bits::comparator::EvaluateLtGadget;
use leo_types::Span; use leo_types::Span;
use snarkos_models::{ use snarkos_models::{
@ -19,9 +20,6 @@ pub fn evaluate_lt<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => { (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
num_1.less_than(unique_namespace, &num_2) num_1.less_than(unique_namespace, &num_2)
} }
(ConstrainedValue::Field(field_1), ConstrainedValue::Field(field_2)) => {
field_1.less_than(unique_namespace, &field_2)
}
(ConstrainedValue::Unresolved(string), val_2) => { (ConstrainedValue::Unresolved(string), val_2) => {
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
return evaluate_lt(&mut unique_namespace, val_1, val_2, span); return evaluate_lt(&mut unique_namespace, val_1, val_2, span);

View File

@ -1,28 +0,0 @@
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
curves::Field,
gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean},
};
pub trait EvaluateLtGadget<F: Field> {
fn less_than<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError>;
}
// implementing `EvaluateLtGadget` will implement `ComparatorGadget`
pub trait ComparatorGadget<F: Field>
where
Self: EvaluateLtGadget<F>,
{
fn greater_than<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
other.less_than(cs, self)
}
fn less_than_or_equal<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
let is_gt = self.greater_than(cs, other)?;
Ok(is_gt.not())
}
fn greater_than_or_equal<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
other.less_than_or_equal(cs, self)
}
}

View File

@ -1,9 +1,6 @@
//! A data type that represents a field value //! A data type that represents a field value
use crate::{ use crate::errors::FieldError;
comparator::{ComparatorGadget, EvaluateLtGadget},
errors::FieldError,
};
use leo_types::Span; use leo_types::Span;
use snarkos_errors::gadgets::SynthesisError; use snarkos_errors::gadgets::SynthesisError;
@ -23,6 +20,7 @@ use snarkos_models::{
}, },
}, },
}; };
use std::{borrow::Borrow, cmp::Ordering}; use std::{borrow::Borrow, cmp::Ordering};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -215,31 +213,6 @@ impl<F: Field + PrimeField> EvaluateEqGadget<F> for FieldType<F> {
} }
} }
impl<F: Field + PrimeField> EvaluateLtGadget<F> for FieldType<F> {
fn less_than<CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
match (self, other) {
(FieldType::Constant(first), FieldType::Constant(second)) => Ok(Boolean::constant(first.lt(second))),
(FieldType::Allocated(allocated), FieldType::Constant(constant))
| (FieldType::Constant(constant), FieldType::Allocated(allocated)) => {
let bool_option = allocated.value.map(|f| f.lt(constant));
Boolean::alloc(&mut cs.ns(|| "less than"), || {
bool_option.ok_or(SynthesisError::AssignmentMissing)
})
}
(FieldType::Allocated(first), FieldType::Allocated(second)) => {
let bool_option = first.value.and_then(|a| second.value.map(|b| a.lt(&b)));
Boolean::alloc(&mut cs.ns(|| "less than"), || {
bool_option.ok_or(SynthesisError::AssignmentMissing)
})
}
}
}
}
impl<F: Field + PrimeField> ComparatorGadget<F> for FieldType<F> {}
impl<F: Field + PrimeField> EqGadget<F> for FieldType<F> {} impl<F: Field + PrimeField> EqGadget<F> for FieldType<F> {}
impl<F: Field + PrimeField> ConditionalEqGadget<F> for FieldType<F> { impl<F: Field + PrimeField> ConditionalEqGadget<F> for FieldType<F> {

View File

@ -1,565 +0,0 @@
//! Conversion of integer declarations to constraints in Leo.
use crate::{
comparator::{ComparatorGadget, EvaluateLtGadget},
errors::IntegerError,
};
use leo_types::{InputValue, IntegerType, Span};
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::{
r1cs::ConstraintSystem,
utilities::{
alloc::AllocGadget,
boolean::Boolean,
eq::{ConditionalEqGadget, EqGadget, EvaluateEqGadget},
select::CondSelectGadget,
uint::{UInt, UInt128, UInt16, UInt32, UInt64, UInt8},
},
},
};
use std::fmt;
/// An integer type enum wrapping the integer value.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
pub enum Integer {
U8(UInt8),
U16(UInt16),
U32(UInt32),
U64(UInt64),
U128(UInt128),
}
impl Integer {
pub fn from_implicit(number: String) -> Self {
Integer::U128(UInt128::constant(number.parse::<u128>().expect("unable to parse u128")))
}
pub fn new_constant(integer_type: &IntegerType, string: String, span: Span) -> Result<Self, IntegerError> {
match integer_type {
IntegerType::U8 => {
let number = string
.parse::<u8>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U8(UInt8::constant(number)))
}
IntegerType::U16 => {
let number = string
.parse::<u16>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U16(UInt16::constant(number)))
}
IntegerType::U32 => {
let number = string
.parse::<u32>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U32(UInt32::constant(number)))
}
IntegerType::U64 => {
let number = string
.parse::<u64>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U64(UInt64::constant(number)))
}
IntegerType::U128 => {
let number = string
.parse::<u128>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U128(UInt128::constant(number)))
}
}
}
pub fn get_value(&self) -> Option<u128> {
match self {
Integer::U8(u8) => u8.value.map(|v| v as u128),
Integer::U16(u16) => u16.value.map(|v| v as u128),
Integer::U32(u32) => u32.value.map(|v| v as u128),
Integer::U64(u64) => u64.value.map(|v| v as u128),
Integer::U128(u128) => u128.value.map(|v| v as u128),
}
}
pub fn to_usize(&self, span: Span) -> Result<usize, IntegerError> {
let value = self.get_value().ok_or(IntegerError::invalid_index(span))?;
Ok(value as usize)
}
pub fn to_bits_le(&self) -> Vec<Boolean> {
match self {
Integer::U8(num) => num.bits.clone(),
Integer::U16(num) => num.bits.clone(),
Integer::U32(num) => num.bits.clone(),
Integer::U64(num) => num.bits.clone(),
Integer::U128(num) => num.bits.clone(),
}
}
pub fn get_type(&self) -> IntegerType {
match self {
Integer::U8(_u8) => IntegerType::U8,
Integer::U16(_u16) => IntegerType::U16,
Integer::U32(_u32) => IntegerType::U32,
Integer::U64(_u64) => IntegerType::U64,
Integer::U128(_u128) => IntegerType::U128,
}
}
pub fn allocate_type<F: Field, CS: ConstraintSystem<F>>(
cs: &mut CS,
integer_type: IntegerType,
name: String,
option: Option<u128>,
span: Span,
) -> Result<Self, IntegerError> {
Ok(match integer_type {
IntegerType::U8 => {
let u8_name = format!("{}: u8", name);
let u8_name_unique = format!("`{}` {}:{}", u8_name, span.line, span.start);
let u8_option = option.map(|integer| integer as u8);
let u8_result = UInt8::alloc(cs.ns(|| u8_name_unique), || {
u8_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u8_name, span))?;
Integer::U8(u8_result)
}
IntegerType::U16 => {
let u16_name = format!("{}: u16", name);
let u16_name_unique = format!("`{}` {}:{}", u16_name, span.line, span.start);
let u16_option = option.map(|integer| integer as u16);
let u16_result = UInt16::alloc(cs.ns(|| u16_name_unique), || {
u16_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u16_name, span))?;
Integer::U16(u16_result)
}
IntegerType::U32 => {
let u32_name = format!("{}: u32", name);
let u32_name_unique = format!("`{}` {}:{}", u32_name, span.line, span.start);
let u32_option = option.map(|integer| integer as u32);
let u32_result = UInt32::alloc(cs.ns(|| u32_name_unique), || {
u32_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u32_name, span))?;
Integer::U32(u32_result)
}
IntegerType::U64 => {
let u64_name = format!("{}: u64", name);
let u64_name_unique = format!("`{}` {}:{}", u64_name, span.line, span.start);
let u64_option = option.map(|integer| integer as u64);
let u64_result = UInt64::alloc(cs.ns(|| u64_name_unique), || {
u64_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u64_name, span))?;
Integer::U64(u64_result)
}
IntegerType::U128 => {
let u128_name = format!("{}: u128", name);
let u128_name_unique = format!("`{}` {}:{}", u128_name, span.line, span.start);
let u128_option = option.map(|integer| integer as u128);
let u128_result = UInt128::alloc(cs.ns(|| u128_name_unique), || {
u128_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u128_name, span))?;
Integer::U128(u128_result)
}
})
}
pub fn from_input<F: Field, CS: ConstraintSystem<F>>(
cs: &mut CS,
integer_type: IntegerType,
name: String,
integer_value: Option<InputValue>,
span: Span,
) -> Result<Self, IntegerError> {
// Check that the input value is the correct type
let option = match integer_value {
Some(input) => {
if let InputValue::Integer(_type_, number) = input {
Some(number)
} else {
return Err(IntegerError::invalid_integer(input.to_string(), span));
}
}
None => None,
};
Self::allocate_type(cs, integer_type, name, option, span)
}
pub fn add<F: Field + PrimeField, CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} + {} {}:{}", self, other, span.line, span.start);
Ok(match (self, other) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
let result = UInt8::addmany(cs.ns(|| unique_namespace), &[left_u8, right_u8])
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
Integer::U8(result)
}
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
let result = UInt16::addmany(cs.ns(|| unique_namespace), &[left_u16, right_u16])
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
Integer::U16(result)
}
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
let result = UInt32::addmany(cs.ns(|| unique_namespace), &[left_u32, right_u32])
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
Integer::U32(result)
}
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
let result = UInt64::addmany(cs.ns(|| unique_namespace), &[left_u64, right_u64])
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
Integer::U64(result)
}
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
let result = UInt128::addmany(cs.ns(|| unique_namespace), &[left_u128, right_u128])
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
Integer::U128(result)
}
(_, _) => return Err(IntegerError::cannot_evaluate(format!("+"), span)),
})
}
pub fn sub<F: Field + PrimeField, CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} - {} {}:{}", self, other, span.line, span.start);
Ok(match (self, other) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
let result = left_u8
.sub(cs.ns(|| unique_namespace), &right_u8)
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
Integer::U8(result)
}
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
let result = left_u16
.sub(cs.ns(|| unique_namespace), &right_u16)
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
Integer::U16(result)
}
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
let result = left_u32
.sub(cs.ns(|| unique_namespace), &right_u32)
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
Integer::U32(result)
}
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
let result = left_u64
.sub(cs.ns(|| unique_namespace), &right_u64)
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
Integer::U64(result)
}
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
let result = left_u128
.sub(cs.ns(|| unique_namespace), &right_u128)
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
Integer::U128(result)
}
(_, _) => return Err(IntegerError::cannot_evaluate(format!("-"), span)),
})
}
pub fn mul<F: Field + PrimeField, CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} * {} {}:{}", self, other, span.line, span.start);
Ok(match (self, other) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
let result = left_u8
.mul(cs.ns(|| unique_namespace), &right_u8)
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
Integer::U8(result)
}
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
let result = left_u16
.mul(cs.ns(|| unique_namespace), &right_u16)
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
Integer::U16(result)
}
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
let result = left_u32
.mul(cs.ns(|| unique_namespace), &right_u32)
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
Integer::U32(result)
}
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
let result = left_u64
.mul(cs.ns(|| unique_namespace), &right_u64)
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
Integer::U64(result)
}
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
let result = left_u128
.mul(cs.ns(|| unique_namespace), &right_u128)
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
Integer::U128(result)
}
(_, _) => return Err(IntegerError::cannot_evaluate(format!("*"), span)),
})
}
pub fn div<F: Field + PrimeField, CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} ÷ {} {}:{}", self, other, span.line, span.start);
Ok(match (self, other) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
let result = left_u8
.div(cs.ns(|| unique_namespace), &right_u8)
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
Integer::U8(result)
}
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
let result = left_u16
.div(cs.ns(|| unique_namespace), &right_u16)
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
Integer::U16(result)
}
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
let result = left_u32
.div(cs.ns(|| unique_namespace), &right_u32)
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
Integer::U32(result)
}
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
let result = left_u64
.div(cs.ns(|| unique_namespace), &right_u64)
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
Integer::U64(result)
}
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
let result = left_u128
.div(cs.ns(|| unique_namespace), &right_u128)
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
Integer::U128(result)
}
(_, _) => return Err(IntegerError::cannot_evaluate(format!("÷"), span)),
})
}
pub fn pow<F: Field + PrimeField, CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} ** {} {}:{}", self, other, span.line, span.start);
Ok(match (self, other) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
let result = left_u8
.pow(cs.ns(|| unique_namespace), &right_u8)
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
Integer::U8(result)
}
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
let result = left_u16
.pow(cs.ns(|| unique_namespace), &right_u16)
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
Integer::U16(result)
}
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
let result = left_u32
.pow(cs.ns(|| unique_namespace), &right_u32)
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
Integer::U32(result)
}
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
let result = left_u64
.pow(cs.ns(|| unique_namespace), &right_u64)
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
Integer::U64(result)
}
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
let result = left_u128
.pow(cs.ns(|| unique_namespace), &right_u128)
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
Integer::U128(result)
}
(_, _) => return Err(IntegerError::cannot_evaluate(format!("**"), span)),
})
}
}
impl<F: Field + PrimeField> EvaluateEqGadget<F> for Integer {
fn evaluate_equal<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
match (self, other) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => left_u8.evaluate_equal(cs, right_u8),
(Integer::U16(left_u16), Integer::U16(right_u16)) => left_u16.evaluate_equal(cs, right_u16),
(Integer::U32(left_u32), Integer::U32(right_u32)) => left_u32.evaluate_equal(cs, right_u32),
(Integer::U64(left_u64), Integer::U64(right_u64)) => left_u64.evaluate_equal(cs, right_u64),
(Integer::U128(left_u128), Integer::U128(right_u128)) => left_u128.evaluate_equal(cs, right_u128),
(_, _) => Err(SynthesisError::AssignmentMissing),
}
}
}
impl<F: Field + PrimeField> EvaluateLtGadget<F> for Integer {
fn less_than<CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
if self.to_bits_le().len() != other.to_bits_le().len() {
return Err(SynthesisError::Unsatisfiable);
}
for (i, (self_bit, other_bit)) in self
.to_bits_le()
.iter()
.rev()
.zip(other.to_bits_le().iter().rev())
.enumerate()
{
// is_greater = a & !b
// only true when a > b
let is_greater = Boolean::and(cs.ns(|| format!("a and not b [{}]", i)), self_bit, &other_bit.not())?;
// is_less = !a & b
// only true when a < b
let is_less = Boolean::and(cs.ns(|| format!("not a and b [{}]", i)), &self_bit.not(), other_bit)?;
if is_greater.get_value().unwrap() {
return Ok(is_greater.not());
} else if is_less.get_value().unwrap() {
return Ok(is_less);
} else if i == self.to_bits_le().len() - 1 {
return Ok(is_less);
}
}
Err(SynthesisError::Unsatisfiable)
}
}
impl<F: Field + PrimeField> ComparatorGadget<F> for Integer {}
impl<F: Field + PrimeField> EqGadget<F> for Integer {}
impl<F: Field + PrimeField> ConditionalEqGadget<F> for Integer {
fn conditional_enforce_equal<CS: ConstraintSystem<F>>(
&self,
cs: CS,
other: &Self,
condition: &Boolean,
) -> Result<(), SynthesisError> {
match (self, other) {
(Integer::U8(left_u8), Integer::U8(right_u8)) => left_u8.conditional_enforce_equal(cs, right_u8, condition),
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
left_u16.conditional_enforce_equal(cs, right_u16, condition)
}
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
left_u32.conditional_enforce_equal(cs, right_u32, condition)
}
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
left_u64.conditional_enforce_equal(cs, right_u64, condition)
}
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
left_u128.conditional_enforce_equal(cs, right_u128, condition)
}
(_, _) => Err(SynthesisError::AssignmentMissing),
}
}
fn cost() -> usize {
<UInt128 as ConditionalEqGadget<F>>::cost()
}
}
impl<F: Field + PrimeField> CondSelectGadget<F> for Integer {
fn conditionally_select<CS: ConstraintSystem<F>>(
cs: CS,
cond: &Boolean,
first: &Self,
second: &Self,
) -> Result<Self, SynthesisError> {
match (first, second) {
(Integer::U8(u8_first), Integer::U8(u8_second)) => {
Ok(Integer::U8(UInt8::conditionally_select(cs, cond, u8_first, u8_second)?))
}
(Integer::U16(u16_first), Integer::U16(u18_second)) => Ok(Integer::U16(UInt16::conditionally_select(
cs, cond, u16_first, u18_second,
)?)),
(Integer::U32(u32_first), Integer::U32(u32_second)) => Ok(Integer::U32(UInt32::conditionally_select(
cs, cond, u32_first, u32_second,
)?)),
(Integer::U64(u64_first), Integer::U64(u64_second)) => Ok(Integer::U64(UInt64::conditionally_select(
cs, cond, u64_first, u64_second,
)?)),
(Integer::U128(u128_first), Integer::U128(u128_second)) => Ok(Integer::U128(
UInt128::conditionally_select(cs, cond, u128_first, u128_second)?,
)),
(_, _) => Err(SynthesisError::Unsatisfiable), // types do not match
}
}
fn cost() -> usize {
unimplemented!("Cannot calculate cost.")
}
}
impl fmt::Display for Integer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let option = match self {
Integer::U8(u8) => u8.value.map(|num| num as u128),
Integer::U16(u16) => u16.value.map(|num| num as u128),
Integer::U32(u32) => u32.value.map(|num| num as u128),
Integer::U64(u64) => u64.value.map(|num| num as u128),
Integer::U128(u128) => u128.value.map(|num| num as u128),
};
match option {
Some(number) => write!(f, "{}{}", number, self.get_type()),
None => write!(f, "[input]{}", self.get_type()),
}
}
}

View File

@ -0,0 +1,507 @@
//! Conversion of integer declarations to constraints in Leo.
use crate::{errors::IntegerError, integer::macros::IntegerTrait};
use leo_gadgets::{
arithmetic::*,
bits::comparator::{ComparatorGadget, EvaluateLtGadget},
signed_integer::*,
};
use leo_types::{InputValue, IntegerType, Span};
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::{
r1cs::ConstraintSystem,
utilities::{
alloc::AllocGadget,
boolean::Boolean,
eq::{ConditionalEqGadget, EqGadget, EvaluateEqGadget},
select::CondSelectGadget,
uint::{UInt, UInt128, UInt16, UInt32, UInt64, UInt8},
},
},
};
use std::fmt;
/// An integer type enum wrapping the integer value.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
pub enum Integer {
U8(UInt8),
U16(UInt16),
U32(UInt32),
U64(UInt64),
U128(UInt128),
I8(Int8),
I16(Int16),
I32(Int32),
I64(Int64),
I128(Int128),
}
impl fmt::Display for Integer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let integer = self;
let option = match_integer!(integer => integer.get_value());
match option {
Some(number) => write!(f, "{}{}", number, self.get_type()),
None => write!(f, "[input]{}", self.get_type()),
}
}
}
impl Integer {
pub fn new_constant(integer_type: &IntegerType, string: String, span: Span) -> Result<Self, IntegerError> {
match integer_type {
IntegerType::U8 => {
let number = string
.parse::<u8>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U8(UInt8::constant(number)))
}
IntegerType::U16 => {
let number = string
.parse::<u16>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U16(UInt16::constant(number)))
}
IntegerType::U32 => {
let number = string
.parse::<u32>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U32(UInt32::constant(number)))
}
IntegerType::U64 => {
let number = string
.parse::<u64>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U64(UInt64::constant(number)))
}
IntegerType::U128 => {
let number = string
.parse::<u128>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::U128(UInt128::constant(number)))
}
IntegerType::I8 => {
let number = string
.parse::<i8>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::I8(Int8::constant(number)))
}
IntegerType::I16 => {
let number = string
.parse::<i16>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::I16(Int16::constant(number)))
}
IntegerType::I32 => {
let number = string
.parse::<i32>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::I32(Int32::constant(number)))
}
IntegerType::I64 => {
let number = string
.parse::<i64>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::I64(Int64::constant(number)))
}
IntegerType::I128 => {
let number = string
.parse::<i128>()
.map_err(|_| IntegerError::invalid_integer(string, span))?;
Ok(Integer::I128(Int128::constant(number)))
}
}
}
pub fn get_bits(&self) -> Vec<Boolean> {
let integer = self;
match_integer!(integer => integer.get_bits())
}
pub fn get_value(&self) -> Option<String> {
let integer = self;
match_integer!(integer => integer.get_value())
}
pub fn to_usize(&self, span: Span) -> Result<usize, IntegerError> {
let value = self.get_value().ok_or(IntegerError::invalid_index(span.clone()))?;
let value_usize = value
.parse::<usize>()
.map_err(|_| IntegerError::invalid_integer(value, span))?;
Ok(value_usize)
}
pub fn get_type(&self) -> IntegerType {
match self {
Integer::U8(_u8) => IntegerType::U8,
Integer::U16(_u16) => IntegerType::U16,
Integer::U32(_u32) => IntegerType::U32,
Integer::U64(_u64) => IntegerType::U64,
Integer::U128(_u128) => IntegerType::U128,
Integer::I8(_u8) => IntegerType::I8,
Integer::I16(_u16) => IntegerType::I16,
Integer::I32(_u32) => IntegerType::I32,
Integer::I64(_u64) => IntegerType::I64,
Integer::I128(_u128) => IntegerType::I128,
}
}
pub fn allocate_type<F: Field, CS: ConstraintSystem<F>>(
cs: &mut CS,
integer_type: IntegerType,
name: String,
option: Option<String>,
span: Span,
) -> Result<Self, IntegerError> {
Ok(match integer_type {
IntegerType::U8 => {
let u8_name = format!("{}: u8", name);
let u8_name_unique = format!("`{}` {}:{}", u8_name, span.line, span.start);
let u8_option = option.map(|s| {
s.parse::<u8>()
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
.unwrap()
});
let u8_result = UInt8::alloc(cs.ns(|| u8_name_unique), || {
u8_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u8_name, span))?;
Integer::U8(u8_result)
}
IntegerType::U16 => {
let u16_name = format!("{}: u16", name);
let u16_name_unique = format!("`{}` {}:{}", u16_name, span.line, span.start);
let u16_option = option.map(|s| {
s.parse::<u16>()
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
.unwrap()
});
let u16_result = UInt16::alloc(cs.ns(|| u16_name_unique), || {
u16_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u16_name, span))?;
Integer::U16(u16_result)
}
IntegerType::U32 => {
let u32_name = format!("{}: u32", name);
let u32_name_unique = format!("`{}` {}:{}", u32_name, span.line, span.start);
let u32_option = option.map(|s| {
s.parse::<u32>()
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
.unwrap()
});
let u32_result = UInt32::alloc(cs.ns(|| u32_name_unique), || {
u32_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u32_name, span))?;
Integer::U32(u32_result)
}
IntegerType::U64 => {
let u64_name = format!("{}: u64", name);
let u64_name_unique = format!("`{}` {}:{}", u64_name, span.line, span.start);
let u64_option = option.map(|s| {
s.parse::<u64>()
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
.unwrap()
});
let u64_result = UInt64::alloc(cs.ns(|| u64_name_unique), || {
u64_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u64_name, span))?;
Integer::U64(u64_result)
}
IntegerType::U128 => {
let u128_name = format!("{}: u128", name);
let u128_name_unique = format!("`{}` {}:{}", u128_name, span.line, span.start);
let u128_option = option.map(|s| {
s.parse::<u128>()
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
.unwrap()
});
let u128_result = UInt128::alloc(cs.ns(|| u128_name_unique), || {
u128_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(u128_name, span))?;
Integer::U128(u128_result)
}
IntegerType::I8 => {
let i8_name = format!("{}: i8", name);
let i8_name_unique = format!("`{}` {}:{}", i8_name, span.line, span.start);
let i8_option = option.map(|s| {
s.parse::<i8>()
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
.unwrap()
});
let i8_result = Int8::alloc(cs.ns(|| i8_name_unique), || {
i8_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(i8_name, span))?;
Integer::I8(i8_result)
}
IntegerType::I16 => {
let i16_name = format!("{}: i16", name);
let i16_name_unique = format!("`{}` {}:{}", i16_name, span.line, span.start);
let i16_option = option.map(|s| {
s.parse::<i16>()
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
.unwrap()
});
let i16_result = Int16::alloc(cs.ns(|| i16_name_unique), || {
i16_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(i16_name, span))?;
Integer::I16(i16_result)
}
IntegerType::I32 => {
let i32_name = format!("{}: i32", name);
let i32_name_unique = format!("`{}` {}:{}", i32_name, span.line, span.start);
let i32_option = option.map(|s| {
s.parse::<i32>()
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
.unwrap()
});
let i32_result = Int32::alloc(cs.ns(|| i32_name_unique), || {
i32_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(i32_name, span))?;
Integer::I32(i32_result)
}
IntegerType::I64 => {
let i64_name = format!("{}: i64", name);
let i64_name_unique = format!("`{}` {}:{}", i64_name, span.line, span.start);
let i64_option = option.map(|s| {
s.parse::<i64>()
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
.unwrap()
});
let i64_result = Int64::alloc(cs.ns(|| i64_name_unique), || {
i64_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(i64_name, span))?;
Integer::I64(i64_result)
}
IntegerType::I128 => {
let i128_name = format!("{}: i128", name);
let i128_name_unique = format!("`{}` {}:{}", i128_name, span.line, span.start);
let i128_option = option.map(|s| {
s.parse::<i128>()
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
.unwrap()
});
let i128_result = Int128::alloc(cs.ns(|| i128_name_unique), || {
i128_option.ok_or(SynthesisError::AssignmentMissing)
})
.map_err(|_| IntegerError::missing_integer(i128_name, span))?;
Integer::I128(i128_result)
}
})
}
pub fn from_input<F: Field, CS: ConstraintSystem<F>>(
cs: &mut CS,
integer_type: IntegerType,
name: String,
integer_value: Option<InputValue>,
span: Span,
) -> Result<Self, IntegerError> {
// Check that the input value is the correct type
let option = match integer_value {
Some(input) => {
if let InputValue::Integer(_type_, number) = input {
Some(number)
} else {
return Err(IntegerError::invalid_integer(input.to_string(), span));
}
}
None => None,
};
Self::allocate_type(cs, integer_type, name, option, span)
}
pub fn add<F: Field + PrimeField, CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} + {} {}:{}", self, other, span.line, span.start);
let a = self;
let b = other;
let s = span.clone();
let result = match_integers_span!((a, b), s => a.add(cs.ns(|| unique_namespace), &b));
result.ok_or(IntegerError::cannot_evaluate(format!("+"), span))
}
pub fn sub<F: Field + PrimeField, CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} - {} {}:{}", self, other, span.line, span.start);
let a = self;
let b = other;
let s = span.clone();
let result = match_integers_span!((a, b), s => a.sub(cs.ns(|| unique_namespace), &b));
result.ok_or(IntegerError::cannot_evaluate(format!("-"), span))
}
pub fn mul<F: Field + PrimeField, CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} * {} {}:{}", self, other, span.line, span.start);
let a = self;
let b = other;
let s = span.clone();
let result = match_integers_span!((a, b), s => a.mul(cs.ns(|| unique_namespace), &b));
result.ok_or(IntegerError::cannot_evaluate(format!("*"), span))
}
pub fn div<F: Field + PrimeField, CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} ÷ {} {}:{}", self, other, span.line, span.start);
let a = self;
let b = other;
let s = span.clone();
let result = match_integers_span!((a, b), s => a.div(cs.ns(|| unique_namespace), &b));
result.ok_or(IntegerError::cannot_evaluate(format!("÷"), span))
}
pub fn pow<F: Field + PrimeField, CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
other: Self,
span: Span,
) -> Result<Self, IntegerError> {
let unique_namespace = format!("enforce {} ** {} {}:{}", self, other, span.line, span.start);
let a = self;
let b = other;
let s = span.clone();
let result = match_integers_span!((a, b), s => a.pow(cs.ns(|| unique_namespace), &b));
result.ok_or(IntegerError::cannot_evaluate(format!("**"), span))
}
}
impl<F: Field + PrimeField> EvaluateEqGadget<F> for Integer {
fn evaluate_equal<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
let a = self;
let b = other;
let result = match_integers!((a, b) => a.evaluate_equal(cs, b));
result.ok_or(SynthesisError::Unsatisfiable)
}
}
impl<F: Field + PrimeField> EvaluateLtGadget<F> for Integer {
fn less_than<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
let a = self;
let b = other;
let result = match_integers!((a, b) => a.less_than(cs, b));
result.ok_or(SynthesisError::Unsatisfiable)
}
}
impl<F: Field + PrimeField> ComparatorGadget<F> for Integer {}
impl<F: Field + PrimeField> EqGadget<F> for Integer {}
impl<F: Field + PrimeField> ConditionalEqGadget<F> for Integer {
fn conditional_enforce_equal<CS: ConstraintSystem<F>>(
&self,
cs: CS,
other: &Self,
condition: &Boolean,
) -> Result<(), SynthesisError> {
let a = self;
let b = other;
let result = match_integers!((a, b) => a.conditional_enforce_equal(cs, b, condition));
result.ok_or(SynthesisError::Unsatisfiable)
}
fn cost() -> usize {
<UInt128 as ConditionalEqGadget<F>>::cost() // upper bound. change trait to increase accuracy
}
}
impl<F: Field + PrimeField> CondSelectGadget<F> for Integer {
fn conditionally_select<CS: ConstraintSystem<F>>(
cs: CS,
cond: &Boolean,
first: &Self,
second: &Self,
) -> Result<Self, SynthesisError> {
match (first, second) {
(Integer::U8(a), Integer::U8(b)) => Ok(Integer::U8(UInt8::conditionally_select(cs, cond, a, b)?)),
(Integer::U16(a), Integer::U16(b)) => Ok(Integer::U16(UInt16::conditionally_select(cs, cond, a, b)?)),
(Integer::U32(a), Integer::U32(b)) => Ok(Integer::U32(UInt32::conditionally_select(cs, cond, a, b)?)),
(Integer::U64(a), Integer::U64(b)) => Ok(Integer::U64(UInt64::conditionally_select(cs, cond, a, b)?)),
(Integer::U128(a), Integer::U128(b)) => Ok(Integer::U128(UInt128::conditionally_select(cs, cond, a, b)?)),
(Integer::I8(a), Integer::I8(b)) => Ok(Integer::I8(Int8::conditionally_select(cs, cond, a, b)?)),
(Integer::I16(a), Integer::I16(b)) => Ok(Integer::I16(Int16::conditionally_select(cs, cond, a, b)?)),
(Integer::I32(a), Integer::I32(b)) => Ok(Integer::I32(Int32::conditionally_select(cs, cond, a, b)?)),
(Integer::I64(a), Integer::I64(b)) => Ok(Integer::I64(Int64::conditionally_select(cs, cond, a, b)?)),
(Integer::I128(a), Integer::I128(b)) => Ok(Integer::I128(Int128::conditionally_select(cs, cond, a, b)?)),
(_, _) => Err(SynthesisError::Unsatisfiable), // types do not match
}
}
fn cost() -> usize {
<UInt128 as CondSelectGadget<F>>::cost() // upper bound. change trait to increase accuracy
}
}

View File

@ -0,0 +1,110 @@
use leo_gadgets::signed_integer::*;
use snarkos_models::gadgets::utilities::{
boolean::Boolean,
uint::{UInt128, UInt16, UInt32, UInt64, UInt8},
};
use std::fmt::Debug;
pub trait IntegerTrait: Sized + Clone + Debug {
fn get_value(&self) -> Option<String>;
fn get_bits(&self) -> Vec<Boolean>;
}
macro_rules! integer_trait_impl {
($($gadget: ident)*) => ($(
impl IntegerTrait for $gadget {
fn get_value(&self) -> Option<String> {
self.value.map(|num| num.to_string())
}
fn get_bits(&self) -> Vec<Boolean> {
self.bits.clone()
}
}
)*)
}
integer_trait_impl!(UInt8 UInt16 UInt32 UInt64 UInt128 Int8 Int16 Int32 Int64 Int128);
/// Useful macros to avoid duplicating `match` constructions.
#[macro_export]
macro_rules! match_integer {
($integer: ident => $expression: expr) => {
match $integer {
Integer::U8($integer) => $expression,
Integer::U16($integer) => $expression,
Integer::U32($integer) => $expression,
Integer::U64($integer) => $expression,
Integer::U128($integer) => $expression,
Integer::I8($integer) => $expression,
Integer::I16($integer) => $expression,
Integer::I32($integer) => $expression,
Integer::I64($integer) => $expression,
Integer::I128($integer) => $expression,
}
};
}
#[macro_export]
macro_rules! match_integers {
(($a: ident, $b: ident) => $expression:expr) => {
match ($a, $b) {
(Integer::U8($a), Integer::U8($b)) => Some($expression?),
(Integer::U16($a), Integer::U16($b)) => Some($expression?),
(Integer::U32($a), Integer::U32($b)) => Some($expression?),
(Integer::U64($a), Integer::U64($b)) => Some($expression?),
(Integer::U128($a), Integer::U128($b)) => Some($expression?),
(Integer::I8($a), Integer::I8($b)) => Some($expression?),
(Integer::I16($a), Integer::I16($b)) => Some($expression?),
(Integer::I32($a), Integer::I32($b)) => Some($expression?),
(Integer::I64($a), Integer::I64($b)) => Some($expression?),
(Integer::I128($a), Integer::I128($b)) => Some($expression?),
(_, _) => None,
}
};
}
#[macro_export]
macro_rules! match_integers_span {
(($a: ident, $b: ident), $span: ident => $expression:expr) => {
match ($a, $b) {
(Integer::U8($a), Integer::U8($b)) => {
Some(Integer::U8($expression.map_err(|e| IntegerError::synthesis(e, $span))?))
}
(Integer::U16($a), Integer::U16($b)) => Some(Integer::U16(
$expression.map_err(|e| IntegerError::synthesis(e, $span))?,
)),
(Integer::U32($a), Integer::U32($b)) => Some(Integer::U32(
$expression.map_err(|e| IntegerError::synthesis(e, $span))?,
)),
(Integer::U64($a), Integer::U64($b)) => Some(Integer::U64(
$expression.map_err(|e| IntegerError::synthesis(e, $span))?,
)),
(Integer::U128($a), Integer::U128($b)) => Some(Integer::U128(
$expression.map_err(|e| IntegerError::synthesis(e, $span))?,
)),
(Integer::I8($a), Integer::I8($b)) => {
Some(Integer::I8($expression.map_err(|e| IntegerError::signed(e, $span))?))
}
(Integer::I16($a), Integer::I16($b)) => {
Some(Integer::I16($expression.map_err(|e| IntegerError::signed(e, $span))?))
}
(Integer::I32($a), Integer::I32($b)) => {
Some(Integer::I32($expression.map_err(|e| IntegerError::signed(e, $span))?))
}
(Integer::I64($a), Integer::I64($b)) => {
Some(Integer::I64($expression.map_err(|e| IntegerError::signed(e, $span))?))
}
(Integer::I128($a), Integer::I128($b)) => {
Some(Integer::I128($expression.map_err(|e| IntegerError::signed(e, $span))?))
}
(_, _) => None,
}
};
}

View File

@ -0,0 +1,6 @@
#[macro_use]
pub mod macros;
pub use self::macros::*;
pub mod integer;
pub use self::integer::*;

View File

@ -5,8 +5,6 @@ pub use self::address::*;
pub mod boolean; pub mod boolean;
pub(crate) mod comparator;
pub mod field; pub mod field;
pub use self::field::*; pub use self::field::*;

View File

@ -191,7 +191,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
ConstrainedValue::Integer(integer) => { ConstrainedValue::Integer(integer) => {
let integer_type = integer.get_type(); let integer_type = integer.get_type();
let option = integer.get_value(); let option = integer.get_value();
let name = option.map(|n| n.to_string()).unwrap_or(format!("[allocated]")); let name = option.clone().unwrap_or(format!("[allocated]"));
*integer = Integer::allocate_type(&mut cs, integer_type, name, option, span)?; *integer = Integer::allocate_type(&mut cs, integer_type, name, option, span)?;
} }

View File

@ -1,3 +1,3 @@
function main() -> u32[3] { function main() -> u32[3] {
return [1u32; 3] return [1u32; 3]
} }

View File

@ -1,3 +1,3 @@
function main() -> u32[3] { function main() -> u32[3] {
return [1u32, 1u32, 1u32] return [1u32, 1u32, 1u32]
} }

View File

@ -1,3 +1,3 @@
function main(arr: u32[3]) -> u32[3] { function main(arr: u32[3]) -> u32[3] {
return arr return arr
} }

View File

@ -55,7 +55,7 @@ fn fail_array(program: EdwardsTestCompiler) {
} }
pub(crate) fn input_value_u32_one() -> InputValue { pub(crate) fn input_value_u32_one() -> InputValue {
InputValue::Integer(IntegerType::U32Type(U32Type {}), 1) InputValue::Integer(IntegerType::U32Type(U32Type {}), 1.to_string())
} }
// Expressions // Expressions

View File

@ -1,8 +1,8 @@
// Multidimensional array syntax in leo // Multidimensional array syntax in leo
function main() -> u32[3][2] { function main() -> u32[3][2] {
const m = [[0u32, 0u32, 0u32], [0u32, 0u32, 0u32]]; // inline const m = [[0u32, 0u32, 0u32], [0u32, 0u32, 0u32]]; // inline
const m: u32[3][2] = [[0; 3]; 2]; // initializer const m: u32[3][2] = [[0; 3]; 2]; // initializer
return m return m
} }

View File

@ -1,6 +1,6 @@
// `{from}..{to}` copies the elements of one array into another exclusively // `{from}..{to}` copies the elements of one array into another exclusively
function main() -> u32[3] { function main() -> u32[3] {
let a = [1u32; 4]; let a = [1u32; 4];
return a[0..3] return a[0..3]
} }

View File

@ -1,6 +1,6 @@
// A spread operator `...` copies the elements of one array into another // A spread operator `...` copies the elements of one array into another
function main() -> u32[3] { function main() -> u32[3] {
let a = [1u32, 1u32]; let a = [1u32, 1u32];
return [1u32, ...a] return [1u32, ...a]
} }

View File

@ -1,8 +1,8 @@
// !(true && (false || true)) // !(true && (false || true))
function main() -> bool { function main() -> bool {
const a = true; const a = true;
const b = false || a; const b = false || a;
const c = !(true && b); const c = !(true && b);
return c return c
} }

View File

@ -1,3 +1,3 @@
function main() -> bool { function main() -> bool {
return false return false
} }

View File

@ -1,3 +1,3 @@
function main() -> bool { function main() -> bool {
return false && false return false && false
} }

View File

@ -1,3 +1,3 @@
function main() -> bool { function main() -> bool {
return false || false return false || false
} }

View File

@ -1,3 +1,3 @@
function main(b: bool) -> bool{ function main(b: bool) -> bool{
return b return b
} }

View File

@ -1,3 +1,3 @@
function main() -> bool { function main() -> bool {
return !false return !false
} }

View File

@ -1,3 +1,3 @@
function main() -> bool { function main() -> bool {
return !true return !true
} }

View File

@ -1,3 +1,3 @@
function main() -> bool { function main() -> bool {
return !1u32 return !1u32
} }

View File

@ -1,3 +1,3 @@
function main() -> bool { function main() -> bool {
return true return true
} }

View File

@ -1,3 +1,3 @@
function main() -> bool { function main() -> bool {
return true && false return true && false
} }

View File

@ -1,3 +1,3 @@
function main() -> bool { function main() -> bool {
return true && true return true && true
} }

View File

@ -1,3 +1,3 @@
function main() -> bool { function main() -> bool {
return true && 1u32 return true && 1u32
} }

View File

@ -1,3 +1,3 @@
function main() -> bool { function main() -> bool {
return true || false return true || false
} }

View File

@ -1,3 +1,3 @@
function main() -> bool { function main() -> bool {
return true || true return true || true
} }

View File

@ -1,3 +1,3 @@
function main() -> bool { function main() -> bool {
return true || 1u32 return true || 1u32
} }

View File

@ -1,7 +1,7 @@
circuit Circ { circuit Foo {
x: u32 x: u32
} }
function main() -> Circ { function main() -> Foo {
return Circ { x: 1u32 } return Foo { x: 1u32 }
} }

View File

@ -1,7 +1,7 @@
circuit Circ { circuit Foo {
x: u32 x: u32
} }
function main() { function main() {
let c = Circ { y: 0u32 }; let c = Foo { y: 0u32 };
} }

View File

@ -1,3 +1,3 @@
function main() { function main() {
let c = Circ { }; let c = Foo { };
} }

View File

@ -1,9 +1,9 @@
circuit Circ { circuit Foo {
x: u32, x: u32,
} }
function main() -> u32 { function main() -> u32 {
let c = Circ { x: 1u32 }; let c = Foo { x: 1u32 };
return c.x return c.x
} }

View File

@ -1,9 +1,9 @@
circuit Circ { circuit Foo {
x: u32 x: u32
} }
function main() -> u32 { function main() -> u32 {
let c = Circ { x: 1u32 }; let c = Foo { x: 1u32 };
return c.y return c.y
} }

View File

@ -1,10 +1,10 @@
circuit Circ { circuit Foo {
function echo(x: u32) -> u32 { function echo(x: u32) -> u32 {
return x return x
} }
} }
function main() -> u32 { function main() -> u32 {
let c = Circ { }; let c = Foo { };
return c.echo(1u32) return c.echo(1u32)
} }

View File

@ -1,10 +1,10 @@
circuit Circ { circuit Foo {
function echo(x: u32) -> u32 { function echo(x: u32) -> u32 {
return x return x
} }
} }
function main() -> u32 { function main() -> u32 {
let c = Circ { }; let c = Foo { };
return c.echoed(1u32) return c.echoed(1u32)
} }

View File

@ -1,10 +1,10 @@
circuit Circ { circuit Foo {
static function echo(x: u32) -> u32 { static function echo(x: u32) -> u32 {
return x return x
} }
} }
function main() -> u32 { function main() -> u32 {
let c = Circ { }; let c = Foo { };
return c.echo(1u32) // echo is a static function and must be accessed using `::` return c.echo(1u32) // echo is a static function and must be accessed using `::`
} }

View File

@ -1,9 +1,9 @@
circuit Circ { circuit Foo {
static function echo(x: u32) -> u32 { static function echo(x: u32) -> u32 {
return x return x
} }
} }
function main() -> u32 { function main() -> u32 {
return Circ::echo(1u32) return Foo::echo(1u32)
} }

View File

@ -1,9 +1,9 @@
circuit Circ { circuit Foo {
function echo(x: u32) -> u32 { function echo(x: u32) -> u32 {
return x return x
} }
} }
function main() -> u32 { function main() -> u32 {
return Circ::echo(1u32) // echo is a non-static function and must be accessed using `.` return Foo::echo(1u32) // echo is a non-static function and must be accessed using `.`
} }

View File

@ -1,9 +1,9 @@
circuit Circ { circuit Foo {
static function echo(x: u32) -> u32 { static function echo(x: u32) -> u32 {
return x return x
} }
} }
function main() -> u32 { function main() -> u32 {
return Circ::echoed(1u32) return Foo::echoed(1u32)
} }

View File

@ -16,13 +16,13 @@ use leo_types::{Expression, Function, Identifier, Span, Statement, Type};
use snarkos_models::gadgets::utilities::uint::UInt32; use snarkos_models::gadgets::utilities::uint::UInt32;
// Circ { x: 1u32 } // Foo { x: 1u32 }
fn output_circuit(program: EdwardsTestCompiler) { fn output_circuit(program: EdwardsTestCompiler) {
let output = get_output(program); let output = get_output(program);
assert_eq!( assert_eq!(
EdwardsConstrainedValue::Return(vec![ConstrainedValue::CircuitExpression( EdwardsConstrainedValue::Return(vec![ConstrainedValue::CircuitExpression(
Identifier { Identifier {
name: "Circ".to_string(), name: "Foo".to_string(),
span: Span { span: Span {
text: "".to_string(), text: "".to_string(),
line: 0, line: 0,
@ -202,7 +202,7 @@ fn test_self_circuit() {
let output = get_output(program); let output = get_output(program);
// circuit Circ { // circuit Foo {
// static function new() -> Self { // static function new() -> Self {
// return Self { } // return Self { }
// } // }
@ -210,7 +210,7 @@ fn test_self_circuit() {
assert_eq!( assert_eq!(
EdwardsConstrainedValue::Return(vec![ConstrainedValue::CircuitExpression( EdwardsConstrainedValue::Return(vec![ConstrainedValue::CircuitExpression(
Identifier { Identifier {
name: "Circ".to_string(), name: "Foo".to_string(),
span: Span { span: Span {
text: "".to_string(), text: "".to_string(),
line: 0, line: 0,

View File

@ -1,9 +1,9 @@
circuit Circ { circuit Foo {
static function new() -> Self { static function new() -> Self {
return Self { } return Self { }
} }
} }
function main() -> Circ { function main() -> Foo {
return Circ::new() return Foo::new()
} }

View File

@ -7,6 +7,6 @@ circuit Foo {
} }
function main() -> u32 { function main() -> u32 {
let circuit = Foo { f: 1u32 }; let foo = Foo { f: 1u32 };
return circuit.bar() return foo.bar()
} }

View File

@ -7,6 +7,6 @@ circuit Foo {
} }
function main() -> u32 { function main() -> u32 {
let circuit = Foo { f: 1u32 }; let foo = Foo { f: 1u32 };
return circuit.bar() return foo.bar()
} }

View File

@ -5,6 +5,6 @@ circuit Foo {
} }
function main() -> u32 { function main() -> u32 {
let circuit = Foo { }; let foo = Foo { };
return circuit.bar() return foo.bar()
} }

View File

@ -1,3 +1,3 @@
function main(a: field, b: field) -> field { function main(a: field, b: field) -> field {
return a + b return a + b
} }

View File

@ -1,3 +1,3 @@
function main(a: field, b: field) { function main(a: field, b: field) {
assert_eq!(a, b); assert_eq!(a, b);
} }

View File

@ -1,3 +1,3 @@
function main(a: field, b: field) -> field { function main(a: field, b: field) -> field {
return a / b return a / b
} }

View File

@ -1,3 +1,3 @@
function main(a: field, b: field) -> bool { function main(a: field, b: field) -> bool {
return a == b return a == b
} }

View File

@ -1,3 +0,0 @@
function main(a: field, b: field) -> bool {
return a >= b
}

View File

@ -1,3 +0,0 @@
function main(a: field, b: field) -> bool {
return a > b
}

View File

@ -1,3 +1,3 @@
function main(f: field) -> field{ function main(f: field) -> field{
return f return f
} }

View File

@ -1,3 +0,0 @@
function main(a: field, b: field) -> bool {
return a <= b
}

View File

@ -1,3 +0,0 @@
function main(a: field, b: field) -> bool {
return a < b
}

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
boolean::{output_expected_boolean, output_false, output_true}, boolean::{output_expected_boolean, output_true},
get_error, get_error,
get_output, get_output,
parse_program, parse_program,
@ -13,6 +13,9 @@ use leo_compiler::{
}; };
use leo_types::InputValue; use leo_types::InputValue;
use num_bigint::BigUint;
use rand::{Rng, SeedableRng};
use rand_xorshift::XorShiftRng;
use snarkos_curves::edwards_bls12::Fq; use snarkos_curves::edwards_bls12::Fq;
use snarkos_gadgets::curves::edwards_bls12::FqGadget; use snarkos_gadgets::curves::edwards_bls12::FqGadget;
use snarkos_models::{ use snarkos_models::{
@ -22,7 +25,7 @@ use snarkos_models::{
r1cs::{ConstraintSystem, TestConstraintSystem}, r1cs::{ConstraintSystem, TestConstraintSystem},
}, },
}; };
use snarkos_utilities::biginteger::BigInteger256; use snarkos_utilities::{biginteger::BigInteger256, bytes::ToBytes};
fn output_expected_constant(program: EdwardsTestCompiler, expected: Fq) { fn output_expected_constant(program: EdwardsTestCompiler, expected: Fq) {
let output = get_output(program); let output = get_output(program);
@ -110,17 +113,22 @@ fn test_input_fail_none() {
fn test_add() { fn test_add() {
use std::ops::Add; use std::ops::Add;
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 { for _ in 0..10 {
let r1: u64 = rand::random(); let r1: Fq = rng.gen();
let r2: u64 = rand::random(); let r2: Fq = rng.gen();
let b1 = BigInteger256::from(r1); let mut r1_buf = Vec::new();
let b2 = BigInteger256::from(r2); let mut r2_buf = Vec::new();
let f1: Fq = Fq::from_repr(b1); r1.write(&mut r1_buf).unwrap();
let f2: Fq = Fq::from_repr(b2); r2.write(&mut r2_buf).unwrap();
let sum = f1.add(&f2); let r1_bigint = BigUint::from_bytes_le(&r1_buf);
let r2_bigint = BigUint::from_bytes_le(&r2_buf);
let sum = r1.add(&r2);
let cs = TestConstraintSystem::<Fq>::new(); let cs = TestConstraintSystem::<Fq>::new();
let sum_allocated = FqGadget::from(cs, &sum); let sum_allocated = FqGadget::from(cs, &sum);
@ -129,8 +137,8 @@ fn test_add() {
let mut program = parse_program(bytes).unwrap(); let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![ program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())), Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2.to_string())), Some(InputValue::Field(r2_bigint.to_str_radix(10))),
]); ]);
output_expected_allocated(program, sum_allocated); output_expected_allocated(program, sum_allocated);
@ -141,17 +149,22 @@ fn test_add() {
fn test_sub() { fn test_sub() {
use std::ops::Sub; use std::ops::Sub;
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 { for _ in 0..10 {
let r1: u64 = rand::random(); let r1: Fq = rng.gen();
let r2: u64 = rand::random(); let r2: Fq = rng.gen();
let b1 = BigInteger256::from(r1); let mut r1_buf = Vec::new();
let b2 = BigInteger256::from(r2); let mut r2_buf = Vec::new();
let f1: Fq = Fq::from_repr(b1); r1.write(&mut r1_buf).unwrap();
let f2: Fq = Fq::from_repr(b2); r2.write(&mut r2_buf).unwrap();
let difference = f1.sub(&f2); let r1_bigint = BigUint::from_bytes_le(&r1_buf);
let r2_bigint = BigUint::from_bytes_le(&r2_buf);
let difference = r1.sub(&r2);
let cs = TestConstraintSystem::<Fq>::new(); let cs = TestConstraintSystem::<Fq>::new();
let difference_allocated = FqGadget::from(cs, &difference); let difference_allocated = FqGadget::from(cs, &difference);
@ -160,8 +173,8 @@ fn test_sub() {
let mut program = parse_program(bytes).unwrap(); let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![ program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())), Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2.to_string())), Some(InputValue::Field(r2_bigint.to_str_radix(10))),
]); ]);
output_expected_allocated(program, difference_allocated); output_expected_allocated(program, difference_allocated);
@ -172,17 +185,22 @@ fn test_sub() {
fn test_mul() { fn test_mul() {
use std::ops::Mul; use std::ops::Mul;
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 { for _ in 0..10 {
let r1: u64 = rand::random(); let r1: Fq = rng.gen();
let r2: u64 = rand::random(); let r2: Fq = rng.gen();
let b1 = BigInteger256::from(r1); let mut r1_buf = Vec::new();
let b2 = BigInteger256::from(r2); let mut r2_buf = Vec::new();
let f1: Fq = Fq::from_repr(b1); r1.write(&mut r1_buf).unwrap();
let f2: Fq = Fq::from_repr(b2); r2.write(&mut r2_buf).unwrap();
let product = f1.mul(&f2); let r1_bigint = BigUint::from_bytes_le(&r1_buf);
let r2_bigint = BigUint::from_bytes_le(&r2_buf);
let product = r1.mul(&r2);
let cs = TestConstraintSystem::<Fq>::new(); let cs = TestConstraintSystem::<Fq>::new();
let product_allocated = FqGadget::from(cs, &product); let product_allocated = FqGadget::from(cs, &product);
@ -191,8 +209,8 @@ fn test_mul() {
let mut program = parse_program(bytes).unwrap(); let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![ program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())), Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2.to_string())), Some(InputValue::Field(r2_bigint.to_str_radix(10))),
]); ]);
output_expected_allocated(program, product_allocated); output_expected_allocated(program, product_allocated);
@ -203,17 +221,22 @@ fn test_mul() {
fn test_div() { fn test_div() {
use std::ops::Div; use std::ops::Div;
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 { for _ in 0..10 {
let r1: u64 = rand::random(); let r1: Fq = rng.gen();
let r2: u64 = rand::random(); let r2: Fq = rng.gen();
let b1 = BigInteger256::from(r1); let mut r1_buf = Vec::new();
let b2 = BigInteger256::from(r2); let mut r2_buf = Vec::new();
let f1: Fq = Fq::from_repr(b1); r1.write(&mut r1_buf).unwrap();
let f2: Fq = Fq::from_repr(b2); r2.write(&mut r2_buf).unwrap();
let quotient = f1.div(&f2); let r1_bigint = BigUint::from_bytes_le(&r1_buf);
let r2_bigint = BigUint::from_bytes_le(&r2_buf);
let quotient = r1.div(&r2);
let cs = TestConstraintSystem::<Fq>::new(); let cs = TestConstraintSystem::<Fq>::new();
let quotient_allocated = FqGadget::from(cs, &quotient); let quotient_allocated = FqGadget::from(cs, &quotient);
@ -222,8 +245,8 @@ fn test_div() {
let mut program = parse_program(bytes).unwrap(); let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![ program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())), Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2.to_string())), Some(InputValue::Field(r2_bigint.to_str_radix(10))),
]); ]);
output_expected_allocated(program, quotient_allocated); output_expected_allocated(program, quotient_allocated);
@ -232,158 +255,42 @@ fn test_div() {
#[test] #[test]
fn test_eq() { fn test_eq() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 { for _ in 0..10 {
let r1: u64 = rand::random(); let r1: Fq = rng.gen();
let r2: Fq = rng.gen();
let mut r1_buf = Vec::new();
let mut r2_buf = Vec::new();
r1.write(&mut r1_buf).unwrap();
r2.write(&mut r2_buf).unwrap();
let r1_bigint = BigUint::from_bytes_le(&r1_buf);
let r2_bigint = BigUint::from_bytes_le(&r2_buf);
// test equal // test equal
let bytes = include_bytes!("eq.leo"); let bytes = include_bytes!("eq.leo");
let mut program = parse_program(bytes).unwrap(); let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![ program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())), Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r1.to_string())), Some(InputValue::Field(r1_bigint.to_str_radix(10))),
]); ]);
output_true(program); output_true(program);
// test not equal // test not equal
let r2: u64 = rand::random();
let result = r1.eq(&r2); let result = r1.eq(&r2);
let mut program = parse_program(bytes).unwrap(); let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![ program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())), Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2.to_string())), Some(InputValue::Field(r2_bigint.to_str_radix(10))),
]);
output_expected_boolean(program, result)
}
}
#[test]
fn test_ge() {
for _ in 0..10 {
let r1: u64 = rand::random();
// test equal
let bytes = include_bytes!("ge.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r1.to_string())),
]);
output_true(program);
// test greater than
let r2: u64 = rand::random();
let result = r1.ge(&r2);
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r2.to_string())),
]);
output_expected_boolean(program, result)
}
}
#[test]
fn test_gt() {
for _ in 0..10 {
let r1: u64 = rand::random();
// test equal
let bytes = include_bytes!("gt.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r1.to_string())),
]);
output_false(program);
// test greater than
let r2: u64 = rand::random();
let result = r1.gt(&r2);
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r2.to_string())),
]);
output_expected_boolean(program, result)
}
}
#[test]
fn test_le() {
for _ in 0..10 {
let r1: u64 = rand::random();
// test equal
let bytes = include_bytes!("le.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r1.to_string())),
]);
output_true(program);
// test greater than
let r2: u64 = rand::random();
let result = r1.le(&r2);
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r2.to_string())),
]);
output_expected_boolean(program, result)
}
}
#[test]
fn test_lt() {
for _ in 0..10 {
let r1: u64 = rand::random();
// test equal
let bytes = include_bytes!("lt.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r1.to_string())),
]);
output_false(program);
// test greater than
let r2: u64 = rand::random();
let result = r1.lt(&r2);
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r2.to_string())),
]); ]);
output_expected_boolean(program, result) output_expected_boolean(program, result)
@ -392,15 +299,20 @@ fn test_lt() {
#[test] #[test]
fn test_assert_eq_pass() { fn test_assert_eq_pass() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 { for _ in 0..10 {
let r1: u64 = rand::random(); let r1: Fq = rng.gen();
let mut r1_buf = Vec::new();
r1.write(&mut r1_buf).unwrap();
let r1_bigint = BigUint::from_bytes_le(&r1_buf);
let bytes = include_bytes!("assert_eq.leo"); let bytes = include_bytes!("assert_eq.leo");
let mut program = parse_program(bytes).unwrap(); let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![ program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())), Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r1.to_string())), Some(InputValue::Field(r1_bigint.to_str_radix(10))),
]); ]);
let _ = get_output(program); let _ = get_output(program);
@ -409,9 +321,18 @@ fn test_assert_eq_pass() {
#[test] #[test]
fn test_assert_eq_fail() { fn test_assert_eq_fail() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for _ in 0..10 { for _ in 0..10 {
let r1: u64 = rand::random(); let r1: Fq = rng.gen();
let r2: u64 = rand::random(); let r2: Fq = rng.gen();
let mut r1_buf = Vec::new();
let mut r2_buf = Vec::new();
r1.write(&mut r1_buf).unwrap();
r2.write(&mut r2_buf).unwrap();
let r1_bigint = BigUint::from_bytes_le(&r1_buf);
let r2_bigint = BigUint::from_bytes_le(&r2_buf);
if r1 == r2 { if r1 == r2 {
continue; continue;
@ -421,8 +342,8 @@ fn test_assert_eq_fail() {
let mut program = parse_program(bytes).unwrap(); let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![ program.set_inputs(vec![
Some(InputValue::Field(r1.to_string())), Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2.to_string())), Some(InputValue::Field(r2_bigint.to_str_radix(10))),
]); ]);
let mut cs = TestConstraintSystem::<Fq>::new(); let mut cs = TestConstraintSystem::<Fq>::new();

View File

@ -1,3 +1,3 @@
function main(a: field, b: field) -> field { function main(a: field, b: field) -> field {
return a * b return a * b
} }

View File

@ -1,3 +1,3 @@
function main() -> field { function main() -> field {
return 1field return 1field
} }

View File

@ -1,3 +1,3 @@
function main(a: field, b: field) -> field { function main(a: field, b: field) -> field {
return a - b return a - b
} }

View File

@ -1,3 +1,3 @@
function main(b: bool, f1: field, f2: field) -> field { function main(b: bool, f1: field, f2: field) -> field {
return if b ? f1 : f2 return if b ? f1 : f2
} }

View File

@ -1,3 +1,3 @@
function main() -> field { function main() -> field {
return 0field return 0field
} }

View File

@ -1,5 +1,5 @@
function empty() { } function empty() { }
function main() { function main() {
empty(); empty();
} }

View File

@ -1,13 +1,13 @@
function one() -> u32 { function one() -> u32 {
return 1u32 return 1u32
} }
function main() -> u32 { function main() -> u32 {
let mut a = 0u32; let mut a = 0u32;
for i in 0..10 { for i in 0..10 {
a += one(); a += one();
} }
return a return a
} }

View File

@ -1,8 +1,8 @@
function test() -> (bool, bool) { function tuple() -> (bool, bool) {
return (true, false) return (true, false)
} }
function main() -> (bool, bool) { function main() -> (bool, bool) {
let (a, b) = test(); let (a, b) = tuple();
return (a, b) return (a, b)
} }

View File

@ -1,3 +1,3 @@
function main() -> (bool, bool) { function main() -> (bool, bool) {
return (true, false) return (true, false)
} }

View File

@ -1,7 +1,7 @@
function test() -> bool { function one() -> bool {
return true return true
} }
function main() -> bool { function main() -> bool {
return test() && test() return one() && one()
} }

View File

@ -1,13 +1,13 @@
function iteration() -> u32 { function iteration() -> u32 {
let mut a = 0u32; let mut a = 0u32;
for i in 0..10 { for i in 0..10 {
a += 1; a += 1;
} }
return a return a
} }
function main() -> u32 { function main() -> u32 {
return iteration() + iteration() return iteration() + iteration()
} }

View File

@ -1,7 +1,7 @@
function one() -> u32 { function one() -> u32 {
return 1u32 return 1u32
} }
function main() -> u32 { function main() -> u32 {
return one() return one()
} }

View File

@ -1,8 +1,8 @@
function foo() -> field { function foo() -> field {
return myGlobal return myGlobal
} }
function main() -> field { function main() -> field {
const myGlobal = 42field; const myGlobal = 42field;
return foo() return foo()
} }

View File

@ -1,3 +1,3 @@
function main() { function main() {
my_function(); my_function();
} }

View File

@ -1,6 +1,6 @@
function main() -> group { function main() -> group {
const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group;
const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group;
return point_1 + point_2 return point_1 + point_2
} }

View File

@ -1,6 +1,6 @@
function main() { function main() {
const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group;
const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group;
assert_eq!(point_1, point_2); assert_eq!(point_1, point_2);
} }

View File

@ -1,6 +1,6 @@
function main() { function main() {
const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group;
const point_2 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; const point_2 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group;
assert_eq!(point_1, point_2); assert_eq!(point_1, point_2);
} }

View File

@ -1,6 +1,6 @@
function main() -> bool { function main() -> bool {
const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group;
const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group;
return point_1 == point_2 return point_1 == point_2
} }

View File

@ -1,6 +1,6 @@
function main() -> bool { function main() -> bool {
const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group;
const point_2 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; const point_2 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group;
return point_1 == point_2 return point_1 == point_2
} }

View File

@ -1,3 +1,3 @@
function main(g: group) -> group { function main(g: group) -> group {
return g return g
} }

View File

@ -1,6 +1,6 @@
function main() -> group { function main() -> group {
const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group;
const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group;
return point_1 - point_2 return point_1 - point_2
} }

View File

@ -1,3 +1,3 @@
function main() -> group { function main() -> group {
return 0group return 0group
} }

View File

@ -1,5 +1,5 @@
import test_import.foo as bar; import test_import.foo as bar;
function main() -> u32 { function main() -> u32 {
return bar() return bar()
} }

View File

@ -1,5 +1,5 @@
import test_import.foo; import test_import.foo;
function main() -> u32 { function main() -> u32 {
return foo() return foo()
} }

View File

@ -1,9 +1,9 @@
import test_import.( import test_import.(
Point, Point,
foo foo
); );
function main() -> u32 { function main() -> u32 {
let p = Point { x: 1u32, y: 0u32 }; let p = Point { x: 1u32, y: 0u32 };
return p.x return p.x
} }

View File

@ -1,6 +1,6 @@
import test_import.*; import test_import.*;
function main() -> u32 { function main() -> u32 {
let p = Point { x: 1u32, y: 0u32 }; let p = Point { x: 1u32, y: 0u32 };
return foo() return foo()
} }

View File

@ -1,3 +1,3 @@
function main(b: bool) -> bool { function main(b: bool) -> bool {
return b return b
} }

View File

@ -1,3 +1,3 @@
function main(a: bool, b: bool) -> bool { function main(a: bool, b: bool) -> bool {
return a || b return a || b
} }

View File

@ -0,0 +1,3 @@
function main(a: i128, b: i128) -> i128 {
return a + b
}

View File

@ -0,0 +1,3 @@
function main(a: i128, b: i128) {
assert_eq!(a, b);
}

View File

@ -0,0 +1,3 @@
function main(a: i128, b: i128) -> i128 {
return a / b
}

View File

@ -0,0 +1,3 @@
function main(a: i128, b: i128) -> bool {
return a == b
}

View File

@ -0,0 +1,3 @@
function main(a: i128, b: i128) -> bool {
return a >= b
}

View File

@ -0,0 +1,3 @@
function main(a: i128, b: i128) -> bool {
return a > b
}

Some files were not shown because too many files have changed in this diff Show More