diff --git a/Cargo.lock b/Cargo.lock index fc4210bdbe..5d59cd1051 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -540,6 +540,7 @@ dependencies = [ "env_logger", "from-pest", "leo-compiler", + "leo-gadgets", "leo-inputs", "log", "rand", @@ -579,11 +580,14 @@ dependencies = [ "bincode", "hex", "leo-ast", + "leo-gadgets", "leo-inputs", "leo-types", "log", + "num-bigint", "pest", "rand", + "rand_xorshift", "sha2", "snarkos-curves", "snarkos-dpc", @@ -595,6 +599,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "leo-gadgets" +version = "0.1.0" +dependencies = [ + "rand", + "rand_xorshift", + "snarkos-errors", + "snarkos-models", + "snarkos-utilities", + "thiserror", +] + [[package]] name = "leo-inputs" version = "0.1.0" @@ -680,6 +696,17 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "num-integer" version = "0.1.43" diff --git a/Cargo.toml b/Cargo.toml index 3a27245863..1fe7d4bb1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,11 +13,12 @@ name = "leo" path = "leo/main.rs" [workspace] -members = [ "ast", "compiler", "leo-inputs", "types" ] +members = [ "ast", "compiler", "gadgets", "leo-inputs", "types" ] [dependencies] 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-curves = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9", default-features = false } diff --git a/ast/src/leo.pest b/ast/src/leo.pest index d77d271753..e292ba698f 100644 --- a/ast/src/leo.pest +++ b/ast/src/leo.pest @@ -81,7 +81,7 @@ operation_gt = { ">" } operation_le = { "<=" } operation_lt = { "<" } operation_add = { "+" } -operation_sub = { "-" } +operation_sub = { "- " } operation_mul = { "*" } operation_div = { "/" } operation_pow = { "**" } @@ -120,13 +120,27 @@ type_integer = { | type_u32 | type_u64 | type_u128 + | type_i8 + | type_i16 + | type_i32 + | type_i64 + | type_i128 } + +// Declared in types/integer.rs type_u8 = { "u8" } type_u16 = { "u16" } type_u32 = { "u32" } type_u64 = { "u64" } 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 type_field = { "field" } @@ -172,7 +186,7 @@ value = { } // 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 value_implicit = { value_number } diff --git a/ast/src/types/integer_type.rs b/ast/src/types/integer_type.rs index 6d74555f09..b0895f073b 100644 --- a/ast/src/types/integer_type.rs +++ b/ast/src/types/integer_type.rs @@ -10,8 +10,16 @@ pub enum IntegerType { U32Type(U32Type), U64Type(U64Type), U128Type(U128Type), + + I8Type(I8Type), + I16Type(I16Type), + I32Type(I32Type), + I64Type(I64Type), + I128Type(I128Type), } +// Unsigned + #[derive(Clone, Debug, FromPest, PartialEq)] #[pest_ast(rule(Rule::type_u8))] pub struct U8Type {} @@ -31,3 +39,25 @@ pub struct U64Type {} #[derive(Clone, Debug, FromPest, PartialEq)] #[pest_ast(rule(Rule::type_u128))] 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 {} diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index dbcdf01c2e..d40dc7f889 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -6,8 +6,9 @@ edition = "2018" [dependencies] 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-types = { path = "../types", version = "0.1.0" } 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 } @@ -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-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-utilities = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9" } + bincode = { version = "1.0" } hex = { version = "0.4.2" } log = { version = "0.4" } pest = { version = "2.0" } rand = { version = "0.7" } +rand_xorshift = { version = "0.2", default-features = false } sha2 = { version = "0.9" } thiserror = { version = "1.0" } [dev-dependencies] -snarkos-utilities = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9" } +num-bigint = { version = "0.3" } diff --git a/compiler/src/errors/value/integer.rs b/compiler/src/errors/value/integer.rs index ae768a7041..9f17f19a31 100644 --- a/compiler/src/errors/value/integer.rs +++ b/compiler/src/errors/value/integer.rs @@ -1,3 +1,4 @@ +use leo_gadgets::errors::SignedIntegerError; use leo_types::{error::Error as FormattedError, Span}; use snarkos_errors::gadgets::SynthesisError; @@ -29,6 +30,27 @@ impl IntegerError { 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 { let message = format!( "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 { - 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) } diff --git a/compiler/src/expression/relational/ge.rs b/compiler/src/expression/relational/ge.rs index f2628a932b..c8c7737f93 100644 --- a/compiler/src/expression/relational/ge.rs +++ b/compiler/src/expression/relational/ge.rs @@ -1,6 +1,7 @@ //! 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 snarkos_models::{ @@ -19,9 +20,6 @@ pub fn evaluate_ge, CS: ConstraintSystem< (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(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) => { let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; return evaluate_ge(&mut unique_namespace, val_1, val_2, span); diff --git a/compiler/src/expression/relational/gt.rs b/compiler/src/expression/relational/gt.rs index 283005f1cf..96ad587219 100644 --- a/compiler/src/expression/relational/gt.rs +++ b/compiler/src/expression/relational/gt.rs @@ -1,6 +1,7 @@ //! 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 snarkos_models::{ @@ -19,9 +20,6 @@ pub fn evaluate_gt, CS: ConstraintSystem< (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(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) => { let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; return evaluate_gt(&mut unique_namespace, val_1, val_2, span); diff --git a/compiler/src/expression/relational/le.rs b/compiler/src/expression/relational/le.rs index 945dae2794..77574e051f 100644 --- a/compiler/src/expression/relational/le.rs +++ b/compiler/src/expression/relational/le.rs @@ -1,6 +1,7 @@ //! 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 snarkos_models::{ @@ -19,9 +20,6 @@ pub fn evaluate_le, CS: ConstraintSystem< (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(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) => { let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; return evaluate_le(&mut unique_namespace, val_1, val_2, span); diff --git a/compiler/src/expression/relational/lt.rs b/compiler/src/expression/relational/lt.rs index 1b8f94a2c0..a5ff4e5222 100644 --- a/compiler/src/expression/relational/lt.rs +++ b/compiler/src/expression/relational/lt.rs @@ -1,6 +1,7 @@ //! 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 snarkos_models::{ @@ -19,9 +20,6 @@ pub fn evaluate_lt, CS: ConstraintSystem< (ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(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) => { let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?; return evaluate_lt(&mut unique_namespace, val_1, val_2, span); diff --git a/compiler/src/value/comparator.rs b/compiler/src/value/comparator.rs deleted file mode 100644 index 34b75ead66..0000000000 --- a/compiler/src/value/comparator.rs +++ /dev/null @@ -1,28 +0,0 @@ -use snarkos_errors::gadgets::SynthesisError; -use snarkos_models::{ - curves::Field, - gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean}, -}; - -pub trait EvaluateLtGadget { - fn less_than>(&self, cs: CS, other: &Self) -> Result; -} - -// implementing `EvaluateLtGadget` will implement `ComparatorGadget` -pub trait ComparatorGadget -where - Self: EvaluateLtGadget, -{ - fn greater_than>(&self, cs: CS, other: &Self) -> Result { - other.less_than(cs, self) - } - - fn less_than_or_equal>(&self, cs: CS, other: &Self) -> Result { - let is_gt = self.greater_than(cs, other)?; - Ok(is_gt.not()) - } - - fn greater_than_or_equal>(&self, cs: CS, other: &Self) -> Result { - other.less_than_or_equal(cs, self) - } -} diff --git a/compiler/src/value/field/field_type.rs b/compiler/src/value/field/field_type.rs index 864c414729..3ec5afce4b 100644 --- a/compiler/src/value/field/field_type.rs +++ b/compiler/src/value/field/field_type.rs @@ -1,9 +1,6 @@ //! A data type that represents a field value -use crate::{ - comparator::{ComparatorGadget, EvaluateLtGadget}, - errors::FieldError, -}; +use crate::errors::FieldError; use leo_types::Span; use snarkos_errors::gadgets::SynthesisError; @@ -23,6 +20,7 @@ use snarkos_models::{ }, }, }; + use std::{borrow::Borrow, cmp::Ordering}; #[derive(Clone, Debug)] @@ -215,31 +213,6 @@ impl EvaluateEqGadget for FieldType { } } -impl EvaluateLtGadget for FieldType { - fn less_than>(&self, mut cs: CS, other: &Self) -> Result { - 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 ComparatorGadget for FieldType {} - impl EqGadget for FieldType {} impl ConditionalEqGadget for FieldType { diff --git a/compiler/src/value/integer.rs b/compiler/src/value/integer.rs deleted file mode 100644 index c16d1991a0..0000000000 --- a/compiler/src/value/integer.rs +++ /dev/null @@ -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::().expect("unable to parse u128"))) - } - - pub fn new_constant(integer_type: &IntegerType, string: String, span: Span) -> Result { - match integer_type { - IntegerType::U8 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span))?; - - Ok(Integer::U8(UInt8::constant(number))) - } - IntegerType::U16 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span))?; - - Ok(Integer::U16(UInt16::constant(number))) - } - IntegerType::U32 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span))?; - - Ok(Integer::U32(UInt32::constant(number))) - } - IntegerType::U64 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span))?; - - Ok(Integer::U64(UInt64::constant(number))) - } - IntegerType::U128 => { - let number = string - .parse::() - .map_err(|_| IntegerError::invalid_integer(string, span))?; - - Ok(Integer::U128(UInt128::constant(number))) - } - } - } - - pub fn get_value(&self) -> Option { - 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 { - let value = self.get_value().ok_or(IntegerError::invalid_index(span))?; - Ok(value as usize) - } - - pub fn to_bits_le(&self) -> Vec { - 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>( - cs: &mut CS, - integer_type: IntegerType, - name: String, - option: Option, - span: Span, - ) -> Result { - 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>( - cs: &mut CS, - integer_type: IntegerType, - name: String, - integer_value: Option, - span: Span, - ) -> Result { - // 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>( - self, - cs: &mut CS, - other: Self, - span: Span, - ) -> Result { - 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>( - self, - cs: &mut CS, - other: Self, - span: Span, - ) -> Result { - 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>( - self, - cs: &mut CS, - other: Self, - span: Span, - ) -> Result { - 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>( - self, - cs: &mut CS, - other: Self, - span: Span, - ) -> Result { - 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>( - self, - cs: &mut CS, - other: Self, - span: Span, - ) -> Result { - 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 EvaluateEqGadget for Integer { - fn evaluate_equal>(&self, cs: CS, other: &Self) -> Result { - 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 EvaluateLtGadget for Integer { - fn less_than>(&self, mut cs: CS, other: &Self) -> Result { - 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 ComparatorGadget for Integer {} - -impl EqGadget for Integer {} - -impl ConditionalEqGadget for Integer { - fn conditional_enforce_equal>( - &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 { - >::cost() - } -} - -impl CondSelectGadget for Integer { - fn conditionally_select>( - cs: CS, - cond: &Boolean, - first: &Self, - second: &Self, - ) -> Result { - 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()), - } - } -} diff --git a/compiler/src/value/integer/integer.rs b/compiler/src/value/integer/integer.rs new file mode 100644 index 0000000000..9c3c6bf715 --- /dev/null +++ b/compiler/src/value/integer/integer.rs @@ -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 { + match integer_type { + IntegerType::U8 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::U8(UInt8::constant(number))) + } + IntegerType::U16 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::U16(UInt16::constant(number))) + } + IntegerType::U32 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::U32(UInt32::constant(number))) + } + IntegerType::U64 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::U64(UInt64::constant(number))) + } + IntegerType::U128 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::U128(UInt128::constant(number))) + } + + IntegerType::I8 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::I8(Int8::constant(number))) + } + IntegerType::I16 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::I16(Int16::constant(number))) + } + IntegerType::I32 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::I32(Int32::constant(number))) + } + IntegerType::I64 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::I64(Int64::constant(number))) + } + IntegerType::I128 => { + let number = string + .parse::() + .map_err(|_| IntegerError::invalid_integer(string, span))?; + + Ok(Integer::I128(Int128::constant(number))) + } + } + } + + pub fn get_bits(&self) -> Vec { + let integer = self; + match_integer!(integer => integer.get_bits()) + } + + pub fn get_value(&self) -> Option { + let integer = self; + match_integer!(integer => integer.get_value()) + } + + pub fn to_usize(&self, span: Span) -> Result { + let value = self.get_value().ok_or(IntegerError::invalid_index(span.clone()))?; + let value_usize = value + .parse::() + .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>( + cs: &mut CS, + integer_type: IntegerType, + name: String, + option: Option, + span: Span, + ) -> Result { + 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::() + .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::() + .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::() + .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::() + .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::() + .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::() + .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::() + .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::() + .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::() + .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::() + .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>( + cs: &mut CS, + integer_type: IntegerType, + name: String, + integer_value: Option, + span: Span, + ) -> Result { + // 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>( + self, + cs: &mut CS, + other: Self, + span: Span, + ) -> Result { + 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>( + self, + cs: &mut CS, + other: Self, + span: Span, + ) -> Result { + 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>( + self, + cs: &mut CS, + other: Self, + span: Span, + ) -> Result { + 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>( + self, + cs: &mut CS, + other: Self, + span: Span, + ) -> Result { + 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>( + self, + cs: &mut CS, + other: Self, + span: Span, + ) -> Result { + 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 EvaluateEqGadget for Integer { + fn evaluate_equal>(&self, cs: CS, other: &Self) -> Result { + let a = self; + let b = other; + + let result = match_integers!((a, b) => a.evaluate_equal(cs, b)); + + result.ok_or(SynthesisError::Unsatisfiable) + } +} + +impl EvaluateLtGadget for Integer { + fn less_than>(&self, cs: CS, other: &Self) -> Result { + let a = self; + let b = other; + let result = match_integers!((a, b) => a.less_than(cs, b)); + + result.ok_or(SynthesisError::Unsatisfiable) + } +} + +impl ComparatorGadget for Integer {} + +impl EqGadget for Integer {} + +impl ConditionalEqGadget for Integer { + fn conditional_enforce_equal>( + &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 { + >::cost() // upper bound. change trait to increase accuracy + } +} + +impl CondSelectGadget for Integer { + fn conditionally_select>( + cs: CS, + cond: &Boolean, + first: &Self, + second: &Self, + ) -> Result { + 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 { + >::cost() // upper bound. change trait to increase accuracy + } +} diff --git a/compiler/src/value/integer/macros.rs b/compiler/src/value/integer/macros.rs new file mode 100644 index 0000000000..03ae2e728e --- /dev/null +++ b/compiler/src/value/integer/macros.rs @@ -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; + + fn get_bits(&self) -> Vec; +} + +macro_rules! integer_trait_impl { + ($($gadget: ident)*) => ($( + impl IntegerTrait for $gadget { + fn get_value(&self) -> Option { + self.value.map(|num| num.to_string()) + } + + fn get_bits(&self) -> Vec { + 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, + } + }; +} diff --git a/compiler/src/value/integer/mod.rs b/compiler/src/value/integer/mod.rs new file mode 100644 index 0000000000..e513df2e0c --- /dev/null +++ b/compiler/src/value/integer/mod.rs @@ -0,0 +1,6 @@ +#[macro_use] +pub mod macros; +pub use self::macros::*; + +pub mod integer; +pub use self::integer::*; diff --git a/compiler/src/value/mod.rs b/compiler/src/value/mod.rs index 095f164bff..654fa0211d 100644 --- a/compiler/src/value/mod.rs +++ b/compiler/src/value/mod.rs @@ -5,8 +5,6 @@ pub use self::address::*; pub mod boolean; -pub(crate) mod comparator; - pub mod field; pub use self::field::*; diff --git a/compiler/src/value/value.rs b/compiler/src/value/value.rs index 9e019284d7..645a008bd8 100644 --- a/compiler/src/value/value.rs +++ b/compiler/src/value/value.rs @@ -191,7 +191,7 @@ impl> ConstrainedValue { ConstrainedValue::Integer(integer) => { let integer_type = integer.get_type(); 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)?; } diff --git a/compiler/tests/array/initializer.leo b/compiler/tests/array/initializer.leo index 744aa39cfa..d129bd704d 100644 --- a/compiler/tests/array/initializer.leo +++ b/compiler/tests/array/initializer.leo @@ -1,3 +1,3 @@ function main() -> u32[3] { - return [1u32; 3] + return [1u32; 3] } \ No newline at end of file diff --git a/compiler/tests/array/inline.leo b/compiler/tests/array/inline.leo index 935e59287f..3a77aa5546 100644 --- a/compiler/tests/array/inline.leo +++ b/compiler/tests/array/inline.leo @@ -1,3 +1,3 @@ function main() -> u32[3] { - return [1u32, 1u32, 1u32] + return [1u32, 1u32, 1u32] } \ No newline at end of file diff --git a/compiler/tests/array/input.leo b/compiler/tests/array/input.leo index dca78cf2a3..eade0fae25 100644 --- a/compiler/tests/array/input.leo +++ b/compiler/tests/array/input.leo @@ -1,3 +1,3 @@ function main(arr: u32[3]) -> u32[3] { - return arr + return arr } \ No newline at end of file diff --git a/compiler/tests/array/mod.rs b/compiler/tests/array/mod.rs index 21c37cc8ce..94886b1527 100644 --- a/compiler/tests/array/mod.rs +++ b/compiler/tests/array/mod.rs @@ -55,7 +55,7 @@ fn fail_array(program: EdwardsTestCompiler) { } pub(crate) fn input_value_u32_one() -> InputValue { - InputValue::Integer(IntegerType::U32Type(U32Type {}), 1) + InputValue::Integer(IntegerType::U32Type(U32Type {}), 1.to_string()) } // Expressions diff --git a/compiler/tests/array/multi.leo b/compiler/tests/array/multi.leo index 7dc37aa8d4..baf94b2842 100644 --- a/compiler/tests/array/multi.leo +++ b/compiler/tests/array/multi.leo @@ -1,8 +1,8 @@ // Multidimensional array syntax in leo 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 } \ No newline at end of file diff --git a/compiler/tests/array/slice.leo b/compiler/tests/array/slice.leo index 7681381ad5..95390d0583 100644 --- a/compiler/tests/array/slice.leo +++ b/compiler/tests/array/slice.leo @@ -1,6 +1,6 @@ // `{from}..{to}` copies the elements of one array into another exclusively function main() -> u32[3] { - let a = [1u32; 4]; + let a = [1u32; 4]; - return a[0..3] + return a[0..3] } diff --git a/compiler/tests/array/spread.leo b/compiler/tests/array/spread.leo index 3db1a1cd1c..86d5612171 100644 --- a/compiler/tests/array/spread.leo +++ b/compiler/tests/array/spread.leo @@ -1,6 +1,6 @@ // A spread operator `...` copies the elements of one array into another function main() -> u32[3] { - let a = [1u32, 1u32]; + let a = [1u32, 1u32]; - return [1u32, ...a] + return [1u32, ...a] } \ No newline at end of file diff --git a/compiler/tests/boolean/all.leo b/compiler/tests/boolean/all.leo index ef95729b4e..f4329b77d5 100644 --- a/compiler/tests/boolean/all.leo +++ b/compiler/tests/boolean/all.leo @@ -1,8 +1,8 @@ // !(true && (false || true)) function main() -> bool { - const a = true; - const b = false || a; - const c = !(true && b); + const a = true; + const b = false || a; + const c = !(true && b); - return c + return c } \ No newline at end of file diff --git a/compiler/tests/boolean/false.leo b/compiler/tests/boolean/false.leo index 22922b0e8f..221958dbd9 100644 --- a/compiler/tests/boolean/false.leo +++ b/compiler/tests/boolean/false.leo @@ -1,3 +1,3 @@ function main() -> bool { - return false + return false } \ No newline at end of file diff --git a/compiler/tests/boolean/false_and_false.leo b/compiler/tests/boolean/false_and_false.leo index 9ce2840a96..4814c7dbb6 100644 --- a/compiler/tests/boolean/false_and_false.leo +++ b/compiler/tests/boolean/false_and_false.leo @@ -1,3 +1,3 @@ function main() -> bool { - return false && false + return false && false } \ No newline at end of file diff --git a/compiler/tests/boolean/false_or_false.leo b/compiler/tests/boolean/false_or_false.leo index dd026b1f29..5e98a6f8c9 100644 --- a/compiler/tests/boolean/false_or_false.leo +++ b/compiler/tests/boolean/false_or_false.leo @@ -1,3 +1,3 @@ function main() -> bool { - return false || false + return false || false } \ No newline at end of file diff --git a/compiler/tests/boolean/input_bool.leo b/compiler/tests/boolean/input_bool.leo index 3536a82621..c233ac7fad 100644 --- a/compiler/tests/boolean/input_bool.leo +++ b/compiler/tests/boolean/input_bool.leo @@ -1,3 +1,3 @@ function main(b: bool) -> bool{ - return b + return b } \ No newline at end of file diff --git a/compiler/tests/boolean/not_false.leo b/compiler/tests/boolean/not_false.leo index ae3c6a0e1a..7a5a8f69a7 100644 --- a/compiler/tests/boolean/not_false.leo +++ b/compiler/tests/boolean/not_false.leo @@ -1,3 +1,3 @@ function main() -> bool { - return !false + return !false } \ No newline at end of file diff --git a/compiler/tests/boolean/not_true.leo b/compiler/tests/boolean/not_true.leo index 650ec54a77..58d3799aed 100644 --- a/compiler/tests/boolean/not_true.leo +++ b/compiler/tests/boolean/not_true.leo @@ -1,3 +1,3 @@ function main() -> bool { - return !true + return !true } \ No newline at end of file diff --git a/compiler/tests/boolean/not_u32.leo b/compiler/tests/boolean/not_u32.leo index 1d4f7ccc20..04b52860ca 100644 --- a/compiler/tests/boolean/not_u32.leo +++ b/compiler/tests/boolean/not_u32.leo @@ -1,3 +1,3 @@ function main() -> bool { - return !1u32 + return !1u32 } \ No newline at end of file diff --git a/compiler/tests/boolean/true.leo b/compiler/tests/boolean/true.leo index 45da76d407..837a259a92 100644 --- a/compiler/tests/boolean/true.leo +++ b/compiler/tests/boolean/true.leo @@ -1,3 +1,3 @@ function main() -> bool { - return true + return true } \ No newline at end of file diff --git a/compiler/tests/boolean/true_and_false.leo b/compiler/tests/boolean/true_and_false.leo index 58c350aedd..531abc407a 100644 --- a/compiler/tests/boolean/true_and_false.leo +++ b/compiler/tests/boolean/true_and_false.leo @@ -1,3 +1,3 @@ function main() -> bool { - return true && false + return true && false } \ No newline at end of file diff --git a/compiler/tests/boolean/true_and_true.leo b/compiler/tests/boolean/true_and_true.leo index a14a9fc29e..e030515842 100644 --- a/compiler/tests/boolean/true_and_true.leo +++ b/compiler/tests/boolean/true_and_true.leo @@ -1,3 +1,3 @@ function main() -> bool { - return true && true + return true && true } \ No newline at end of file diff --git a/compiler/tests/boolean/true_and_u32.leo b/compiler/tests/boolean/true_and_u32.leo index 9e0cc52314..d466f63a3e 100644 --- a/compiler/tests/boolean/true_and_u32.leo +++ b/compiler/tests/boolean/true_and_u32.leo @@ -1,3 +1,3 @@ function main() -> bool { - return true && 1u32 + return true && 1u32 } \ No newline at end of file diff --git a/compiler/tests/boolean/true_or_false.leo b/compiler/tests/boolean/true_or_false.leo index 0682912527..cdb0ff3484 100644 --- a/compiler/tests/boolean/true_or_false.leo +++ b/compiler/tests/boolean/true_or_false.leo @@ -1,3 +1,3 @@ function main() -> bool { - return true || false + return true || false } \ No newline at end of file diff --git a/compiler/tests/boolean/true_or_true.leo b/compiler/tests/boolean/true_or_true.leo index 33551d2d7d..0451e20b75 100644 --- a/compiler/tests/boolean/true_or_true.leo +++ b/compiler/tests/boolean/true_or_true.leo @@ -1,3 +1,3 @@ function main() -> bool { - return true || true + return true || true } \ No newline at end of file diff --git a/compiler/tests/boolean/true_or_u32.leo b/compiler/tests/boolean/true_or_u32.leo index e96064e747..bd12e19708 100644 --- a/compiler/tests/boolean/true_or_u32.leo +++ b/compiler/tests/boolean/true_or_u32.leo @@ -1,3 +1,3 @@ function main() -> bool { - return true || 1u32 + return true || 1u32 } \ No newline at end of file diff --git a/compiler/tests/circuits/inline.leo b/compiler/tests/circuits/inline.leo index ab96e20c5e..0a9af217ff 100644 --- a/compiler/tests/circuits/inline.leo +++ b/compiler/tests/circuits/inline.leo @@ -1,7 +1,7 @@ -circuit Circ { - x: u32 +circuit Foo { + x: u32 } -function main() -> Circ { - return Circ { x: 1u32 } +function main() -> Foo { + return Foo { x: 1u32 } } \ No newline at end of file diff --git a/compiler/tests/circuits/inline_fail.leo b/compiler/tests/circuits/inline_fail.leo index 8e9043cbe4..d5690cca95 100644 --- a/compiler/tests/circuits/inline_fail.leo +++ b/compiler/tests/circuits/inline_fail.leo @@ -1,7 +1,7 @@ -circuit Circ { - x: u32 +circuit Foo { + x: u32 } function main() { - let c = Circ { y: 0u32 }; + let c = Foo { y: 0u32 }; } \ No newline at end of file diff --git a/compiler/tests/circuits/inline_undefined.leo b/compiler/tests/circuits/inline_undefined.leo index e1a1099173..2167ed7160 100644 --- a/compiler/tests/circuits/inline_undefined.leo +++ b/compiler/tests/circuits/inline_undefined.leo @@ -1,3 +1,3 @@ function main() { - let c = Circ { }; + let c = Foo { }; } \ No newline at end of file diff --git a/compiler/tests/circuits/member_field.leo b/compiler/tests/circuits/member_field.leo index b9e7b7d88e..9cb2955ca3 100644 --- a/compiler/tests/circuits/member_field.leo +++ b/compiler/tests/circuits/member_field.leo @@ -1,9 +1,9 @@ -circuit Circ { - x: u32, +circuit Foo { + x: u32, } function main() -> u32 { - let c = Circ { x: 1u32 }; + let c = Foo { x: 1u32 }; - return c.x + return c.x } \ No newline at end of file diff --git a/compiler/tests/circuits/member_field_fail.leo b/compiler/tests/circuits/member_field_fail.leo index d763606f4b..643ac3dbff 100644 --- a/compiler/tests/circuits/member_field_fail.leo +++ b/compiler/tests/circuits/member_field_fail.leo @@ -1,9 +1,9 @@ -circuit Circ { - x: u32 +circuit Foo { + x: u32 } function main() -> u32 { - let c = Circ { x: 1u32 }; + let c = Foo { x: 1u32 }; - return c.y + return c.y } \ No newline at end of file diff --git a/compiler/tests/circuits/member_function.leo b/compiler/tests/circuits/member_function.leo index 169f4491d9..4528b0e5e0 100644 --- a/compiler/tests/circuits/member_function.leo +++ b/compiler/tests/circuits/member_function.leo @@ -1,10 +1,10 @@ -circuit Circ { - function echo(x: u32) -> u32 { - return x - } +circuit Foo { + function echo(x: u32) -> u32 { + return x + } } function main() -> u32 { - let c = Circ { }; - return c.echo(1u32) + let c = Foo { }; + return c.echo(1u32) } \ No newline at end of file diff --git a/compiler/tests/circuits/member_function_fail.leo b/compiler/tests/circuits/member_function_fail.leo index 282b16a8b6..7facc85cd5 100644 --- a/compiler/tests/circuits/member_function_fail.leo +++ b/compiler/tests/circuits/member_function_fail.leo @@ -1,10 +1,10 @@ -circuit Circ { - function echo(x: u32) -> u32 { - return x - } +circuit Foo { + function echo(x: u32) -> u32 { + return x + } } function main() -> u32 { - let c = Circ { }; - return c.echoed(1u32) + let c = Foo { }; + return c.echoed(1u32) } \ No newline at end of file diff --git a/compiler/tests/circuits/member_function_invalid.leo b/compiler/tests/circuits/member_function_invalid.leo index b5a85537e7..b882433dda 100644 --- a/compiler/tests/circuits/member_function_invalid.leo +++ b/compiler/tests/circuits/member_function_invalid.leo @@ -1,10 +1,10 @@ -circuit Circ { - static function echo(x: u32) -> u32 { - return x - } +circuit Foo { + static function echo(x: u32) -> u32 { + return x + } } function main() -> u32 { - let c = Circ { }; - return c.echo(1u32) // echo is a static function and must be accessed using `::` + let c = Foo { }; + return c.echo(1u32) // echo is a static function and must be accessed using `::` } \ No newline at end of file diff --git a/compiler/tests/circuits/member_static_function.leo b/compiler/tests/circuits/member_static_function.leo index 20e1fa7bdf..34814d15bd 100644 --- a/compiler/tests/circuits/member_static_function.leo +++ b/compiler/tests/circuits/member_static_function.leo @@ -1,9 +1,9 @@ -circuit Circ { - static function echo(x: u32) -> u32 { - return x - } +circuit Foo { + static function echo(x: u32) -> u32 { + return x + } } function main() -> u32 { - return Circ::echo(1u32) + return Foo::echo(1u32) } \ No newline at end of file diff --git a/compiler/tests/circuits/member_static_function_invalid.leo b/compiler/tests/circuits/member_static_function_invalid.leo index 821341b79e..54a1879d1a 100644 --- a/compiler/tests/circuits/member_static_function_invalid.leo +++ b/compiler/tests/circuits/member_static_function_invalid.leo @@ -1,9 +1,9 @@ -circuit Circ { - function echo(x: u32) -> u32 { - return x - } +circuit Foo { + function echo(x: u32) -> u32 { + return x + } } 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 `.` } \ No newline at end of file diff --git a/compiler/tests/circuits/member_static_function_undefined.leo b/compiler/tests/circuits/member_static_function_undefined.leo index 2de29b4464..8ded0d7619 100644 --- a/compiler/tests/circuits/member_static_function_undefined.leo +++ b/compiler/tests/circuits/member_static_function_undefined.leo @@ -1,9 +1,9 @@ -circuit Circ { - static function echo(x: u32) -> u32 { - return x - } +circuit Foo { + static function echo(x: u32) -> u32 { + return x + } } function main() -> u32 { - return Circ::echoed(1u32) + return Foo::echoed(1u32) } \ No newline at end of file diff --git a/compiler/tests/circuits/mod.rs b/compiler/tests/circuits/mod.rs index 6f7589f1aa..46784d01e4 100644 --- a/compiler/tests/circuits/mod.rs +++ b/compiler/tests/circuits/mod.rs @@ -16,13 +16,13 @@ use leo_types::{Expression, Function, Identifier, Span, Statement, Type}; use snarkos_models::gadgets::utilities::uint::UInt32; -// Circ { x: 1u32 } +// Foo { x: 1u32 } fn output_circuit(program: EdwardsTestCompiler) { let output = get_output(program); assert_eq!( EdwardsConstrainedValue::Return(vec![ConstrainedValue::CircuitExpression( Identifier { - name: "Circ".to_string(), + name: "Foo".to_string(), span: Span { text: "".to_string(), line: 0, @@ -202,7 +202,7 @@ fn test_self_circuit() { let output = get_output(program); - // circuit Circ { + // circuit Foo { // static function new() -> Self { // return Self { } // } @@ -210,7 +210,7 @@ fn test_self_circuit() { assert_eq!( EdwardsConstrainedValue::Return(vec![ConstrainedValue::CircuitExpression( Identifier { - name: "Circ".to_string(), + name: "Foo".to_string(), span: Span { text: "".to_string(), line: 0, diff --git a/compiler/tests/circuits/self_circuit.leo b/compiler/tests/circuits/self_circuit.leo index cbee731017..12713ed214 100644 --- a/compiler/tests/circuits/self_circuit.leo +++ b/compiler/tests/circuits/self_circuit.leo @@ -1,9 +1,9 @@ -circuit Circ { - static function new() -> Self { - return Self { } - } +circuit Foo { + static function new() -> Self { + return Self { } + } } -function main() -> Circ { - return Circ::new() +function main() -> Foo { + return Foo::new() } \ No newline at end of file diff --git a/compiler/tests/circuits/self_member.leo b/compiler/tests/circuits/self_member.leo index a1401e15d3..9e5701385e 100644 --- a/compiler/tests/circuits/self_member.leo +++ b/compiler/tests/circuits/self_member.leo @@ -7,6 +7,6 @@ circuit Foo { } function main() -> u32 { - let circuit = Foo { f: 1u32 }; - return circuit.bar() + let foo = Foo { f: 1u32 }; + return foo.bar() } \ No newline at end of file diff --git a/compiler/tests/circuits/self_member_fail.leo b/compiler/tests/circuits/self_member_fail.leo index 53050fcb5b..78f8811b5f 100644 --- a/compiler/tests/circuits/self_member_fail.leo +++ b/compiler/tests/circuits/self_member_fail.leo @@ -7,6 +7,6 @@ circuit Foo { } function main() -> u32 { - let circuit = Foo { f: 1u32 }; - return circuit.bar() + let foo = Foo { f: 1u32 }; + return foo.bar() } \ No newline at end of file diff --git a/compiler/tests/circuits/self_no_member_fail.leo b/compiler/tests/circuits/self_no_member_fail.leo index bfc5b57e31..6bafa9ae9d 100644 --- a/compiler/tests/circuits/self_no_member_fail.leo +++ b/compiler/tests/circuits/self_no_member_fail.leo @@ -5,6 +5,6 @@ circuit Foo { } function main() -> u32 { - let circuit = Foo { }; - return circuit.bar() + let foo = Foo { }; + return foo.bar() } \ No newline at end of file diff --git a/compiler/tests/field/add.leo b/compiler/tests/field/add.leo index a99723ef76..90a5d093b1 100644 --- a/compiler/tests/field/add.leo +++ b/compiler/tests/field/add.leo @@ -1,3 +1,3 @@ function main(a: field, b: field) -> field { - return a + b + return a + b } \ No newline at end of file diff --git a/compiler/tests/field/assert_eq.leo b/compiler/tests/field/assert_eq.leo index ebf7eecb1a..a5dbe51c6a 100644 --- a/compiler/tests/field/assert_eq.leo +++ b/compiler/tests/field/assert_eq.leo @@ -1,3 +1,3 @@ function main(a: field, b: field) { - assert_eq!(a, b); + assert_eq!(a, b); } \ No newline at end of file diff --git a/compiler/tests/field/div.leo b/compiler/tests/field/div.leo index 6214073024..f4b3378ebb 100644 --- a/compiler/tests/field/div.leo +++ b/compiler/tests/field/div.leo @@ -1,3 +1,3 @@ function main(a: field, b: field) -> field { - return a / b + return a / b } \ No newline at end of file diff --git a/compiler/tests/field/eq.leo b/compiler/tests/field/eq.leo index 839bf5d64e..0739f2baab 100644 --- a/compiler/tests/field/eq.leo +++ b/compiler/tests/field/eq.leo @@ -1,3 +1,3 @@ function main(a: field, b: field) -> bool { - return a == b + return a == b } \ No newline at end of file diff --git a/compiler/tests/field/ge.leo b/compiler/tests/field/ge.leo deleted file mode 100644 index 860cdfc695..0000000000 --- a/compiler/tests/field/ge.leo +++ /dev/null @@ -1,3 +0,0 @@ -function main(a: field, b: field) -> bool { - return a >= b -} \ No newline at end of file diff --git a/compiler/tests/field/gt.leo b/compiler/tests/field/gt.leo deleted file mode 100644 index 4bec88c764..0000000000 --- a/compiler/tests/field/gt.leo +++ /dev/null @@ -1,3 +0,0 @@ -function main(a: field, b: field) -> bool { - return a > b -} \ No newline at end of file diff --git a/compiler/tests/field/input.leo b/compiler/tests/field/input.leo index 29ff4f08b2..1b49fb06e3 100644 --- a/compiler/tests/field/input.leo +++ b/compiler/tests/field/input.leo @@ -1,3 +1,3 @@ function main(f: field) -> field{ - return f + return f } \ No newline at end of file diff --git a/compiler/tests/field/le.leo b/compiler/tests/field/le.leo deleted file mode 100644 index 8cdc10e5c4..0000000000 --- a/compiler/tests/field/le.leo +++ /dev/null @@ -1,3 +0,0 @@ -function main(a: field, b: field) -> bool { - return a <= b -} \ No newline at end of file diff --git a/compiler/tests/field/lt.leo b/compiler/tests/field/lt.leo deleted file mode 100644 index 4e4acf457c..0000000000 --- a/compiler/tests/field/lt.leo +++ /dev/null @@ -1,3 +0,0 @@ -function main(a: field, b: field) -> bool { - return a < b -} \ No newline at end of file diff --git a/compiler/tests/field/mod.rs b/compiler/tests/field/mod.rs index 77087b4abc..48aa04b1d6 100644 --- a/compiler/tests/field/mod.rs +++ b/compiler/tests/field/mod.rs @@ -1,5 +1,5 @@ use crate::{ - boolean::{output_expected_boolean, output_false, output_true}, + boolean::{output_expected_boolean, output_true}, get_error, get_output, parse_program, @@ -13,6 +13,9 @@ use leo_compiler::{ }; use leo_types::InputValue; +use num_bigint::BigUint; +use rand::{Rng, SeedableRng}; +use rand_xorshift::XorShiftRng; use snarkos_curves::edwards_bls12::Fq; use snarkos_gadgets::curves::edwards_bls12::FqGadget; use snarkos_models::{ @@ -22,7 +25,7 @@ use snarkos_models::{ r1cs::{ConstraintSystem, TestConstraintSystem}, }, }; -use snarkos_utilities::biginteger::BigInteger256; +use snarkos_utilities::{biginteger::BigInteger256, bytes::ToBytes}; fn output_expected_constant(program: EdwardsTestCompiler, expected: Fq) { let output = get_output(program); @@ -110,17 +113,22 @@ fn test_input_fail_none() { fn test_add() { use std::ops::Add; + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + for _ in 0..10 { - let r1: u64 = rand::random(); - let r2: u64 = rand::random(); + let r1: Fq = rng.gen(); + let r2: Fq = rng.gen(); - let b1 = BigInteger256::from(r1); - let b2 = BigInteger256::from(r2); + let mut r1_buf = Vec::new(); + let mut r2_buf = Vec::new(); - let f1: Fq = Fq::from_repr(b1); - let f2: Fq = Fq::from_repr(b2); + r1.write(&mut r1_buf).unwrap(); + 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::::new(); let sum_allocated = FqGadget::from(cs, &sum); @@ -129,8 +137,8 @@ fn test_add() { let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Field(r1.to_string())), - Some(InputValue::Field(r2.to_string())), + Some(InputValue::Field(r1_bigint.to_str_radix(10))), + Some(InputValue::Field(r2_bigint.to_str_radix(10))), ]); output_expected_allocated(program, sum_allocated); @@ -141,17 +149,22 @@ fn test_add() { fn test_sub() { use std::ops::Sub; + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + for _ in 0..10 { - let r1: u64 = rand::random(); - let r2: u64 = rand::random(); + let r1: Fq = rng.gen(); + let r2: Fq = rng.gen(); - let b1 = BigInteger256::from(r1); - let b2 = BigInteger256::from(r2); + let mut r1_buf = Vec::new(); + let mut r2_buf = Vec::new(); - let f1: Fq = Fq::from_repr(b1); - let f2: Fq = Fq::from_repr(b2); + r1.write(&mut r1_buf).unwrap(); + 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::::new(); let difference_allocated = FqGadget::from(cs, &difference); @@ -160,8 +173,8 @@ fn test_sub() { let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Field(r1.to_string())), - Some(InputValue::Field(r2.to_string())), + Some(InputValue::Field(r1_bigint.to_str_radix(10))), + Some(InputValue::Field(r2_bigint.to_str_radix(10))), ]); output_expected_allocated(program, difference_allocated); @@ -172,17 +185,22 @@ fn test_sub() { fn test_mul() { use std::ops::Mul; + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + for _ in 0..10 { - let r1: u64 = rand::random(); - let r2: u64 = rand::random(); + let r1: Fq = rng.gen(); + let r2: Fq = rng.gen(); - let b1 = BigInteger256::from(r1); - let b2 = BigInteger256::from(r2); + let mut r1_buf = Vec::new(); + let mut r2_buf = Vec::new(); - let f1: Fq = Fq::from_repr(b1); - let f2: Fq = Fq::from_repr(b2); + r1.write(&mut r1_buf).unwrap(); + 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::::new(); let product_allocated = FqGadget::from(cs, &product); @@ -191,8 +209,8 @@ fn test_mul() { let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Field(r1.to_string())), - Some(InputValue::Field(r2.to_string())), + Some(InputValue::Field(r1_bigint.to_str_radix(10))), + Some(InputValue::Field(r2_bigint.to_str_radix(10))), ]); output_expected_allocated(program, product_allocated); @@ -203,17 +221,22 @@ fn test_mul() { fn test_div() { use std::ops::Div; + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + for _ in 0..10 { - let r1: u64 = rand::random(); - let r2: u64 = rand::random(); + let r1: Fq = rng.gen(); + let r2: Fq = rng.gen(); - let b1 = BigInteger256::from(r1); - let b2 = BigInteger256::from(r2); + let mut r1_buf = Vec::new(); + let mut r2_buf = Vec::new(); - let f1: Fq = Fq::from_repr(b1); - let f2: Fq = Fq::from_repr(b2); + r1.write(&mut r1_buf).unwrap(); + 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::::new(); let quotient_allocated = FqGadget::from(cs, "ient); @@ -222,8 +245,8 @@ fn test_div() { let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Field(r1.to_string())), - Some(InputValue::Field(r2.to_string())), + Some(InputValue::Field(r1_bigint.to_str_radix(10))), + Some(InputValue::Field(r2_bigint.to_str_radix(10))), ]); output_expected_allocated(program, quotient_allocated); @@ -232,158 +255,42 @@ fn test_div() { #[test] fn test_eq() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + 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 + let bytes = include_bytes!("eq.leo"); let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Field(r1.to_string())), - Some(InputValue::Field(r1.to_string())), + Some(InputValue::Field(r1_bigint.to_str_radix(10))), + Some(InputValue::Field(r1_bigint.to_str_radix(10))), ]); output_true(program); // test not equal - let r2: u64 = rand::random(); let result = r1.eq(&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_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())), + Some(InputValue::Field(r1_bigint.to_str_radix(10))), + Some(InputValue::Field(r2_bigint.to_str_radix(10))), ]); output_expected_boolean(program, result) @@ -392,15 +299,20 @@ fn test_lt() { #[test] fn test_assert_eq_pass() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + 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 mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Field(r1.to_string())), - Some(InputValue::Field(r1.to_string())), + Some(InputValue::Field(r1_bigint.to_str_radix(10))), + Some(InputValue::Field(r1_bigint.to_str_radix(10))), ]); let _ = get_output(program); @@ -409,9 +321,18 @@ fn test_assert_eq_pass() { #[test] fn test_assert_eq_fail() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + for _ in 0..10 { - let r1: u64 = rand::random(); - let r2: 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); if r1 == r2 { continue; @@ -421,8 +342,8 @@ fn test_assert_eq_fail() { let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Field(r1.to_string())), - Some(InputValue::Field(r2.to_string())), + Some(InputValue::Field(r1_bigint.to_str_radix(10))), + Some(InputValue::Field(r2_bigint.to_str_radix(10))), ]); let mut cs = TestConstraintSystem::::new(); diff --git a/compiler/tests/field/mul.leo b/compiler/tests/field/mul.leo index 8223cc8bc8..5a383183e8 100644 --- a/compiler/tests/field/mul.leo +++ b/compiler/tests/field/mul.leo @@ -1,3 +1,3 @@ function main(a: field, b: field) -> field { - return a * b + return a * b } \ No newline at end of file diff --git a/compiler/tests/field/one.leo b/compiler/tests/field/one.leo index ff579fe6c8..d97c60e14f 100644 --- a/compiler/tests/field/one.leo +++ b/compiler/tests/field/one.leo @@ -1,3 +1,3 @@ function main() -> field { - return 1field + return 1field } \ No newline at end of file diff --git a/compiler/tests/field/sub.leo b/compiler/tests/field/sub.leo index 7c49a87da8..c304200040 100644 --- a/compiler/tests/field/sub.leo +++ b/compiler/tests/field/sub.leo @@ -1,3 +1,3 @@ function main(a: field, b: field) -> field { - return a - b + return a - b } \ No newline at end of file diff --git a/compiler/tests/field/ternary.leo b/compiler/tests/field/ternary.leo index c85ac6a764..108ec6cdb1 100644 --- a/compiler/tests/field/ternary.leo +++ b/compiler/tests/field/ternary.leo @@ -1,3 +1,3 @@ function main(b: bool, f1: field, f2: field) -> field { - return if b ? f1 : f2 + return if b ? f1 : f2 } \ No newline at end of file diff --git a/compiler/tests/field/zero.leo b/compiler/tests/field/zero.leo index 7794442505..9a12e8aac0 100644 --- a/compiler/tests/field/zero.leo +++ b/compiler/tests/field/zero.leo @@ -1,3 +1,3 @@ function main() -> field { - return 0field + return 0field } \ No newline at end of file diff --git a/compiler/tests/function/empty.leo b/compiler/tests/function/empty.leo index b433132a2f..f06c976158 100644 --- a/compiler/tests/function/empty.leo +++ b/compiler/tests/function/empty.leo @@ -1,5 +1,5 @@ function empty() { } function main() { - empty(); + empty(); } \ No newline at end of file diff --git a/compiler/tests/function/iteration.leo b/compiler/tests/function/iteration.leo index ef967c2b0a..7a0229049f 100644 --- a/compiler/tests/function/iteration.leo +++ b/compiler/tests/function/iteration.leo @@ -1,13 +1,13 @@ function one() -> u32 { - return 1u32 + return 1u32 } function main() -> u32 { - let mut a = 0u32; + let mut a = 0u32; - for i in 0..10 { - a += one(); - } + for i in 0..10 { + a += one(); + } - return a + return a } \ No newline at end of file diff --git a/compiler/tests/function/multiple.leo b/compiler/tests/function/multiple.leo index 53439ef706..88baba4a3b 100644 --- a/compiler/tests/function/multiple.leo +++ b/compiler/tests/function/multiple.leo @@ -1,8 +1,8 @@ -function test() -> (bool, bool) { - return (true, false) +function tuple() -> (bool, bool) { + return (true, false) } function main() -> (bool, bool) { - let (a, b) = test(); - return (a, b) + let (a, b) = tuple(); + return (a, b) } \ No newline at end of file diff --git a/compiler/tests/function/multiple_main.leo b/compiler/tests/function/multiple_main.leo index 4e00a8743c..c1e5d41276 100644 --- a/compiler/tests/function/multiple_main.leo +++ b/compiler/tests/function/multiple_main.leo @@ -1,3 +1,3 @@ function main() -> (bool, bool) { - return (true, false) + return (true, false) } \ No newline at end of file diff --git a/compiler/tests/function/repeated.leo b/compiler/tests/function/repeated.leo index cef685c9a8..238f6b1931 100644 --- a/compiler/tests/function/repeated.leo +++ b/compiler/tests/function/repeated.leo @@ -1,7 +1,7 @@ -function test() -> bool { - return true +function one() -> bool { + return true } function main() -> bool { - return test() && test() + return one() && one() } \ No newline at end of file diff --git a/compiler/tests/function/repeated_iteration.leo b/compiler/tests/function/repeated_iteration.leo index d667e9fc25..5db3b04df7 100644 --- a/compiler/tests/function/repeated_iteration.leo +++ b/compiler/tests/function/repeated_iteration.leo @@ -1,13 +1,13 @@ function iteration() -> u32 { - let mut a = 0u32; + let mut a = 0u32; - for i in 0..10 { - a += 1; - } + for i in 0..10 { + a += 1; + } - return a + return a } function main() -> u32 { - return iteration() + iteration() + return iteration() + iteration() } \ No newline at end of file diff --git a/compiler/tests/function/return.leo b/compiler/tests/function/return.leo index 6cb1dbcb72..a2ccc954c6 100644 --- a/compiler/tests/function/return.leo +++ b/compiler/tests/function/return.leo @@ -1,7 +1,7 @@ function one() -> u32 { - return 1u32 + return 1u32 } function main() -> u32 { - return one() + return one() } \ No newline at end of file diff --git a/compiler/tests/function/scope_fail.leo b/compiler/tests/function/scope_fail.leo index e25a0f1e6b..32777e9ebf 100644 --- a/compiler/tests/function/scope_fail.leo +++ b/compiler/tests/function/scope_fail.leo @@ -1,8 +1,8 @@ function foo() -> field { - return myGlobal + return myGlobal } function main() -> field { - const myGlobal = 42field; - return foo() + const myGlobal = 42field; + return foo() } \ No newline at end of file diff --git a/compiler/tests/function/undefined.leo b/compiler/tests/function/undefined.leo index 8274668d84..e1db3b9f09 100644 --- a/compiler/tests/function/undefined.leo +++ b/compiler/tests/function/undefined.leo @@ -1,3 +1,3 @@ function main() { - my_function(); + my_function(); } \ No newline at end of file diff --git a/compiler/tests/group/add.leo b/compiler/tests/group/add.leo index 28cbcd67b8..fe3839ba47 100644 --- a/compiler/tests/group/add.leo +++ b/compiler/tests/group/add.leo @@ -1,6 +1,6 @@ function main() -> group { - const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; + const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; - return point_1 + point_2 + return point_1 + point_2 } \ No newline at end of file diff --git a/compiler/tests/group/assert_eq_false.leo b/compiler/tests/group/assert_eq_false.leo index 5e130610aa..63d8d428d2 100644 --- a/compiler/tests/group/assert_eq_false.leo +++ b/compiler/tests/group/assert_eq_false.leo @@ -1,6 +1,6 @@ function main() { - const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; + const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; - assert_eq!(point_1, point_2); + assert_eq!(point_1, point_2); } \ No newline at end of file diff --git a/compiler/tests/group/assert_eq_true.leo b/compiler/tests/group/assert_eq_true.leo index fecce61611..91b1e560cd 100644 --- a/compiler/tests/group/assert_eq_true.leo +++ b/compiler/tests/group/assert_eq_true.leo @@ -1,6 +1,6 @@ function main() { - const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - const point_2 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_2 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - assert_eq!(point_1, point_2); + assert_eq!(point_1, point_2); } \ No newline at end of file diff --git a/compiler/tests/group/eq_false.leo b/compiler/tests/group/eq_false.leo index 004c44b731..8aea82b204 100644 --- a/compiler/tests/group/eq_false.leo +++ b/compiler/tests/group/eq_false.leo @@ -1,6 +1,6 @@ function main() -> bool { - const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; + const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; - return point_1 == point_2 + return point_1 == point_2 } \ No newline at end of file diff --git a/compiler/tests/group/eq_true.leo b/compiler/tests/group/eq_true.leo index 490c0e9432..7759c33fd5 100644 --- a/compiler/tests/group/eq_true.leo +++ b/compiler/tests/group/eq_true.leo @@ -1,6 +1,6 @@ function main() -> bool { - const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - const point_2 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_2 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - return point_1 == point_2 + return point_1 == point_2 } \ No newline at end of file diff --git a/compiler/tests/group/input.leo b/compiler/tests/group/input.leo index 8191078634..f19fb29b23 100644 --- a/compiler/tests/group/input.leo +++ b/compiler/tests/group/input.leo @@ -1,3 +1,3 @@ function main(g: group) -> group { - return g + return g } \ No newline at end of file diff --git a/compiler/tests/group/sub.leo b/compiler/tests/group/sub.leo index a1f95b5a3c..adf9a4542b 100644 --- a/compiler/tests/group/sub.leo +++ b/compiler/tests/group/sub.leo @@ -1,6 +1,6 @@ function main() -> group { - const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; + const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; - return point_1 - point_2 + return point_1 - point_2 } \ No newline at end of file diff --git a/compiler/tests/group/zero.leo b/compiler/tests/group/zero.leo index 789937bbad..298cf5fe2e 100644 --- a/compiler/tests/group/zero.leo +++ b/compiler/tests/group/zero.leo @@ -1,3 +1,3 @@ function main() -> group { - return 0group + return 0group } \ No newline at end of file diff --git a/compiler/tests/import/alias.leo b/compiler/tests/import/alias.leo index 8035ee6c76..9236d8f01f 100644 --- a/compiler/tests/import/alias.leo +++ b/compiler/tests/import/alias.leo @@ -1,5 +1,5 @@ import test_import.foo as bar; function main() -> u32 { - return bar() + return bar() } \ No newline at end of file diff --git a/compiler/tests/import/basic.leo b/compiler/tests/import/basic.leo index 8166710c7a..4aa4fa050e 100644 --- a/compiler/tests/import/basic.leo +++ b/compiler/tests/import/basic.leo @@ -1,5 +1,5 @@ import test_import.foo; function main() -> u32 { - return foo() + return foo() } \ No newline at end of file diff --git a/compiler/tests/import/multiple.leo b/compiler/tests/import/multiple.leo index ddf9093347..38b2c2e301 100644 --- a/compiler/tests/import/multiple.leo +++ b/compiler/tests/import/multiple.leo @@ -1,9 +1,9 @@ import test_import.( - Point, - foo + Point, + foo ); function main() -> u32 { - let p = Point { x: 1u32, y: 0u32 }; - return p.x + let p = Point { x: 1u32, y: 0u32 }; + return p.x } \ No newline at end of file diff --git a/compiler/tests/import/star.leo b/compiler/tests/import/star.leo index 113adc7088..ccc876600c 100644 --- a/compiler/tests/import/star.leo +++ b/compiler/tests/import/star.leo @@ -1,6 +1,6 @@ import test_import.*; function main() -> u32 { - let p = Point { x: 1u32, y: 0u32 }; - return foo() + let p = Point { x: 1u32, y: 0u32 }; + return foo() } \ No newline at end of file diff --git a/compiler/tests/inputs/main.leo b/compiler/tests/inputs/main.leo index b1ba0090ef..7e2a1c7e0c 100644 --- a/compiler/tests/inputs/main.leo +++ b/compiler/tests/inputs/main.leo @@ -1,3 +1,3 @@ function main(b: bool) -> bool { - return b + return b } \ No newline at end of file diff --git a/compiler/tests/inputs/main_multiple.leo b/compiler/tests/inputs/main_multiple.leo index 90c58d23d2..e2231f14bc 100644 --- a/compiler/tests/inputs/main_multiple.leo +++ b/compiler/tests/inputs/main_multiple.leo @@ -1,3 +1,3 @@ function main(a: bool, b: bool) -> bool { - return a || b + return a || b } \ No newline at end of file diff --git a/compiler/tests/integers/i128/add.leo b/compiler/tests/integers/i128/add.leo new file mode 100644 index 0000000000..1a90ea377d --- /dev/null +++ b/compiler/tests/integers/i128/add.leo @@ -0,0 +1,3 @@ +function main(a: i128, b: i128) -> i128 { + return a + b +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/assert_eq.leo b/compiler/tests/integers/i128/assert_eq.leo new file mode 100644 index 0000000000..a6dc495a84 --- /dev/null +++ b/compiler/tests/integers/i128/assert_eq.leo @@ -0,0 +1,3 @@ +function main(a: i128, b: i128) { + assert_eq!(a, b); +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/div.leo b/compiler/tests/integers/i128/div.leo new file mode 100644 index 0000000000..e2f9f2853e --- /dev/null +++ b/compiler/tests/integers/i128/div.leo @@ -0,0 +1,3 @@ +function main(a: i128, b: i128) -> i128 { + return a / b +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/eq.leo b/compiler/tests/integers/i128/eq.leo new file mode 100644 index 0000000000..5681aa7263 --- /dev/null +++ b/compiler/tests/integers/i128/eq.leo @@ -0,0 +1,3 @@ +function main(a: i128, b: i128) -> bool { + return a == b +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/ge.leo b/compiler/tests/integers/i128/ge.leo new file mode 100644 index 0000000000..05949082f4 --- /dev/null +++ b/compiler/tests/integers/i128/ge.leo @@ -0,0 +1,3 @@ +function main(a: i128, b: i128) -> bool { + return a >= b +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/gt.leo b/compiler/tests/integers/i128/gt.leo new file mode 100644 index 0000000000..5eedfa3ec0 --- /dev/null +++ b/compiler/tests/integers/i128/gt.leo @@ -0,0 +1,3 @@ +function main(a: i128, b: i128) -> bool { + return a > b +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/input.leo b/compiler/tests/integers/i128/input.leo new file mode 100644 index 0000000000..aa49ca84f8 --- /dev/null +++ b/compiler/tests/integers/i128/input.leo @@ -0,0 +1,3 @@ +function main(x: i128) -> i128 { + return x +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/le.leo b/compiler/tests/integers/i128/le.leo new file mode 100644 index 0000000000..472e1f53ce --- /dev/null +++ b/compiler/tests/integers/i128/le.leo @@ -0,0 +1,3 @@ +function main(a: i128, b: i128) -> bool { + return a <= b +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/lt.leo b/compiler/tests/integers/i128/lt.leo new file mode 100644 index 0000000000..610a51e55f --- /dev/null +++ b/compiler/tests/integers/i128/lt.leo @@ -0,0 +1,3 @@ +function main(a: i128, b: i128) -> bool { + return a < b +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/max.leo b/compiler/tests/integers/i128/max.leo new file mode 100644 index 0000000000..06bf685187 --- /dev/null +++ b/compiler/tests/integers/i128/max.leo @@ -0,0 +1,3 @@ +function main() -> i128 { + return 170141183460469231731687303715884105727 +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/min.leo b/compiler/tests/integers/i128/min.leo new file mode 100644 index 0000000000..1f90232344 --- /dev/null +++ b/compiler/tests/integers/i128/min.leo @@ -0,0 +1,3 @@ +function main() -> i128 { + return -170141183460469231731687303715884105728 +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/mod.rs b/compiler/tests/integers/i128/mod.rs new file mode 100644 index 0000000000..6b9f332e3e --- /dev/null +++ b/compiler/tests/integers/i128/mod.rs @@ -0,0 +1,105 @@ +use crate::{ + boolean::{output_expected_boolean, output_false, output_true}, + get_error, + get_output, + integers::{fail_integer, IntegerTester}, + parse_program, + EdwardsConstrainedValue, + EdwardsTestCompiler, +}; +use leo_compiler::{ConstrainedValue, Integer}; +use leo_gadgets::*; +use leo_inputs::types::{I128Type, IntegerType}; +use leo_types::InputValue; + +use snarkos_curves::edwards_bls12::Fq; +use snarkos_models::gadgets::{r1cs::TestConstraintSystem, utilities::alloc::AllocGadget}; + +fn output_expected_allocated(program: EdwardsTestCompiler, expected: Int128) { + let output = get_output(program); + + match output { + EdwardsConstrainedValue::Return(vec) => match vec.as_slice() { + [ConstrainedValue::Integer(Integer::I128(actual))] => assert_eq!(*actual, expected), + _ => panic!("program output unknown return value"), + }, + _ => panic!("program output unknown return value"), + } +} + +test_int!(TestI128, i128, IntegerType::I128Type(I128Type {}), Int128); + +#[test] +fn test_i128_min() { + TestI128::test_min(std::i128::MIN); +} + +#[test] +fn test_i128_max() { + TestI128::test_max(std::i128::MAX); +} + +#[test] +fn test_i128_input() { + TestI128::test_input(); +} + +#[test] +fn test_i128_add() { + TestI128::test_add(); +} + +#[test] +fn test_i128_sub() { + TestI128::test_sub(); +} + +#[test] +fn test_i128_mul() { + TestI128::test_mul(); +} + +#[test] +fn test_i128_div() { + TestI128::test_div(); +} + +#[test] +fn test_i128_pow() { + TestI128::test_pow(); +} + +#[test] +fn test_i128_eq() { + TestI128::test_eq(); +} + +#[test] +fn test_i128_ge() { + TestI128::test_ge(); +} + +#[test] +fn test_i128_gt() { + TestI128::test_gt(); +} + +#[test] +fn test_i128_le() { + TestI128::test_le(); +} + +#[test] +fn test_i128_lt() { + TestI128::test_lt(); +} + +#[test] +fn test_i128_assert_eq() { + TestI128::test_assert_eq(); +} + +#[test] +fn test_i128_ternary() { + TestI128::test_ternary(); +} diff --git a/compiler/tests/integers/i128/mul.leo b/compiler/tests/integers/i128/mul.leo new file mode 100644 index 0000000000..1d2595ca16 --- /dev/null +++ b/compiler/tests/integers/i128/mul.leo @@ -0,0 +1,3 @@ +function main(a: i128, b: i128) -> i128 { + return a * b +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/one.leo b/compiler/tests/integers/i128/one.leo new file mode 100644 index 0000000000..94313ac666 --- /dev/null +++ b/compiler/tests/integers/i128/one.leo @@ -0,0 +1,3 @@ +function main() -> i128 { + return 1 +} diff --git a/compiler/tests/integers/i128/pow.leo b/compiler/tests/integers/i128/pow.leo new file mode 100644 index 0000000000..c98bdcfe0d --- /dev/null +++ b/compiler/tests/integers/i128/pow.leo @@ -0,0 +1,3 @@ +function main(a: i128, b: i128) -> i128 { + return a ** b +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/sub.leo b/compiler/tests/integers/i128/sub.leo new file mode 100644 index 0000000000..87e617798f --- /dev/null +++ b/compiler/tests/integers/i128/sub.leo @@ -0,0 +1,3 @@ +function main(a: i128, b: i128) -> i128 { + return a - b +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/ternary.leo b/compiler/tests/integers/i128/ternary.leo new file mode 100644 index 0000000000..cb1ff53c68 --- /dev/null +++ b/compiler/tests/integers/i128/ternary.leo @@ -0,0 +1,3 @@ +function main(b: bool, x: i128, y: i128) -> i128 { + return if b ? x : y +} \ No newline at end of file diff --git a/compiler/tests/integers/i128/zero.leo b/compiler/tests/integers/i128/zero.leo new file mode 100644 index 0000000000..e58cdfd4ff --- /dev/null +++ b/compiler/tests/integers/i128/zero.leo @@ -0,0 +1,3 @@ +function main() -> i128 { + return 0 +} diff --git a/compiler/tests/integers/i16/add.leo b/compiler/tests/integers/i16/add.leo new file mode 100644 index 0000000000..44486b97ee --- /dev/null +++ b/compiler/tests/integers/i16/add.leo @@ -0,0 +1,3 @@ +function main(a: i16, b: i16) -> i16 { + return a + b +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/assert_eq.leo b/compiler/tests/integers/i16/assert_eq.leo new file mode 100644 index 0000000000..4bc5fffcad --- /dev/null +++ b/compiler/tests/integers/i16/assert_eq.leo @@ -0,0 +1,3 @@ +function main(a: i16, b: i16) { + assert_eq!(a, b); +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/div.leo b/compiler/tests/integers/i16/div.leo new file mode 100644 index 0000000000..ea4d4ecded --- /dev/null +++ b/compiler/tests/integers/i16/div.leo @@ -0,0 +1,3 @@ +function main(a: i16, b: i16) -> i16 { + return a / b +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/eq.leo b/compiler/tests/integers/i16/eq.leo new file mode 100644 index 0000000000..1ea29bd65e --- /dev/null +++ b/compiler/tests/integers/i16/eq.leo @@ -0,0 +1,3 @@ +function main(a: i16, b: i16) -> bool { + return a == b +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/ge.leo b/compiler/tests/integers/i16/ge.leo new file mode 100644 index 0000000000..51bb45b725 --- /dev/null +++ b/compiler/tests/integers/i16/ge.leo @@ -0,0 +1,3 @@ +function main(a: i16, b: i16) -> bool { + return a >= b +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/gt.leo b/compiler/tests/integers/i16/gt.leo new file mode 100644 index 0000000000..2a6eeac47a --- /dev/null +++ b/compiler/tests/integers/i16/gt.leo @@ -0,0 +1,3 @@ +function main(a: i16, b: i16) -> bool { + return a > b +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/input.leo b/compiler/tests/integers/i16/input.leo new file mode 100644 index 0000000000..c4cb048ff6 --- /dev/null +++ b/compiler/tests/integers/i16/input.leo @@ -0,0 +1,3 @@ +function main(x: i16) -> i16 { + return x +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/le.leo b/compiler/tests/integers/i16/le.leo new file mode 100644 index 0000000000..cd6d0eb87b --- /dev/null +++ b/compiler/tests/integers/i16/le.leo @@ -0,0 +1,3 @@ +function main(a: i16, b: i16) -> bool { + return a <= b +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/lt.leo b/compiler/tests/integers/i16/lt.leo new file mode 100644 index 0000000000..cfdfd24bcb --- /dev/null +++ b/compiler/tests/integers/i16/lt.leo @@ -0,0 +1,3 @@ +function main(a: i16, b: i16) -> bool { + return a < b +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/max.leo b/compiler/tests/integers/i16/max.leo new file mode 100644 index 0000000000..df19a40dd2 --- /dev/null +++ b/compiler/tests/integers/i16/max.leo @@ -0,0 +1,3 @@ +function main() -> i16 { + return 32767 +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/min.leo b/compiler/tests/integers/i16/min.leo new file mode 100644 index 0000000000..3d5949f073 --- /dev/null +++ b/compiler/tests/integers/i16/min.leo @@ -0,0 +1,3 @@ +function main() -> i16 { + return -32768 +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/mod.rs b/compiler/tests/integers/i16/mod.rs new file mode 100644 index 0000000000..bddaeb84be --- /dev/null +++ b/compiler/tests/integers/i16/mod.rs @@ -0,0 +1,105 @@ +use crate::{ + boolean::{output_expected_boolean, output_false, output_true}, + get_error, + get_output, + integers::{fail_integer, IntegerTester}, + parse_program, + EdwardsConstrainedValue, + EdwardsTestCompiler, +}; +use leo_compiler::{ConstrainedValue, Integer}; +use leo_gadgets::*; +use leo_inputs::types::{I16Type, IntegerType}; +use leo_types::InputValue; + +use snarkos_curves::edwards_bls12::Fq; +use snarkos_models::gadgets::{r1cs::TestConstraintSystem, utilities::alloc::AllocGadget}; + +fn output_expected_allocated(program: EdwardsTestCompiler, expected: Int16) { + let output = get_output(program); + + match output { + EdwardsConstrainedValue::Return(vec) => match vec.as_slice() { + [ConstrainedValue::Integer(Integer::I16(actual))] => assert_eq!(*actual, expected), + _ => panic!("program output unknown return value"), + }, + _ => panic!("program output unknown return value"), + } +} + +test_int!(TestI16, i16, IntegerType::I16Type(I16Type {}), Int16); + +#[test] +fn test_i16_min() { + TestI16::test_min(std::i16::MIN); +} + +#[test] +fn test_i16_max() { + TestI16::test_max(std::i16::MAX); +} + +#[test] +fn test_i16_input() { + TestI16::test_input(); +} + +#[test] +fn test_i16_add() { + TestI16::test_add(); +} + +#[test] +fn test_i16_sub() { + TestI16::test_sub(); +} + +#[test] +fn test_i16_mul() { + TestI16::test_mul(); +} + +#[test] +fn test_i16_div() { + TestI16::test_div(); +} + +#[test] +fn test_i16_pow() { + TestI16::test_pow(); +} + +#[test] +fn test_i16_eq() { + TestI16::test_eq(); +} + +#[test] +fn test_i16_ge() { + TestI16::test_ge(); +} + +#[test] +fn test_i16_gt() { + TestI16::test_gt(); +} + +#[test] +fn test_i16_le() { + TestI16::test_le(); +} + +#[test] +fn test_i16_lt() { + TestI16::test_lt(); +} + +#[test] +fn test_i16_assert_eq() { + TestI16::test_assert_eq(); +} + +#[test] +fn test_i16_ternary() { + TestI16::test_ternary(); +} diff --git a/compiler/tests/integers/i16/mul.leo b/compiler/tests/integers/i16/mul.leo new file mode 100644 index 0000000000..ce0eb504fc --- /dev/null +++ b/compiler/tests/integers/i16/mul.leo @@ -0,0 +1,3 @@ +function main(a: i16, b: i16) -> i16 { + return a * b +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/one.leo b/compiler/tests/integers/i16/one.leo new file mode 100644 index 0000000000..40af477ea3 --- /dev/null +++ b/compiler/tests/integers/i16/one.leo @@ -0,0 +1,3 @@ +function main() -> i16 { + return 1 +} diff --git a/compiler/tests/integers/i16/pow.leo b/compiler/tests/integers/i16/pow.leo new file mode 100644 index 0000000000..ca18827873 --- /dev/null +++ b/compiler/tests/integers/i16/pow.leo @@ -0,0 +1,3 @@ +function main(a: i16, b: i16) -> i16 { + return a ** b +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/sub.leo b/compiler/tests/integers/i16/sub.leo new file mode 100644 index 0000000000..608aac1793 --- /dev/null +++ b/compiler/tests/integers/i16/sub.leo @@ -0,0 +1,3 @@ +function main(a: i16, b: i16) -> i16 { + return a - b +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/ternary.leo b/compiler/tests/integers/i16/ternary.leo new file mode 100644 index 0000000000..21d92e0818 --- /dev/null +++ b/compiler/tests/integers/i16/ternary.leo @@ -0,0 +1,3 @@ +function main(b: bool, x: i16, y: i16) -> i16 { + return if b ? x : y +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/zero.leo b/compiler/tests/integers/i16/zero.leo new file mode 100644 index 0000000000..781030f10a --- /dev/null +++ b/compiler/tests/integers/i16/zero.leo @@ -0,0 +1,3 @@ +function main() -> i16 { + return 0 +} diff --git a/compiler/tests/integers/i32/add.leo b/compiler/tests/integers/i32/add.leo new file mode 100644 index 0000000000..9c7e8f6433 --- /dev/null +++ b/compiler/tests/integers/i32/add.leo @@ -0,0 +1,3 @@ +function main(a: i32, b: i32) -> i32 { + return a + b +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/assert_eq.leo b/compiler/tests/integers/i32/assert_eq.leo new file mode 100644 index 0000000000..326cca12b6 --- /dev/null +++ b/compiler/tests/integers/i32/assert_eq.leo @@ -0,0 +1,3 @@ +function main(a: i32, b: i32) { + assert_eq!(a, b); +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/div.leo b/compiler/tests/integers/i32/div.leo new file mode 100644 index 0000000000..3b1392a921 --- /dev/null +++ b/compiler/tests/integers/i32/div.leo @@ -0,0 +1,3 @@ +function main(a: i32, b: i32) -> i32 { + return a / b +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/eq.leo b/compiler/tests/integers/i32/eq.leo new file mode 100644 index 0000000000..b3284a07d0 --- /dev/null +++ b/compiler/tests/integers/i32/eq.leo @@ -0,0 +1,3 @@ +function main(a: i32, b: i32) -> bool { + return a == b +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/ge.leo b/compiler/tests/integers/i32/ge.leo new file mode 100644 index 0000000000..073955b53f --- /dev/null +++ b/compiler/tests/integers/i32/ge.leo @@ -0,0 +1,3 @@ +function main(a: i32, b: i32) -> bool { + return a >= b +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/gt.leo b/compiler/tests/integers/i32/gt.leo new file mode 100644 index 0000000000..acf027eade --- /dev/null +++ b/compiler/tests/integers/i32/gt.leo @@ -0,0 +1,3 @@ +function main(a: i32, b: i32) -> bool { + return a > b +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/input.leo b/compiler/tests/integers/i32/input.leo new file mode 100644 index 0000000000..ea6d7f9d30 --- /dev/null +++ b/compiler/tests/integers/i32/input.leo @@ -0,0 +1,3 @@ +function main(x: i32) -> i32 { + return x +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/le.leo b/compiler/tests/integers/i32/le.leo new file mode 100644 index 0000000000..5f2615cd0a --- /dev/null +++ b/compiler/tests/integers/i32/le.leo @@ -0,0 +1,3 @@ +function main(a: i32, b: i32) -> bool { + return a <= b +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/lt.leo b/compiler/tests/integers/i32/lt.leo new file mode 100644 index 0000000000..aea55410fa --- /dev/null +++ b/compiler/tests/integers/i32/lt.leo @@ -0,0 +1,3 @@ +function main(a: i32, b: i32) -> bool { + return a < b +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/max.leo b/compiler/tests/integers/i32/max.leo new file mode 100644 index 0000000000..d5e3a94dd4 --- /dev/null +++ b/compiler/tests/integers/i32/max.leo @@ -0,0 +1,3 @@ +function main() -> i32 { + return 2147483647 +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/min.leo b/compiler/tests/integers/i32/min.leo new file mode 100644 index 0000000000..1625435322 --- /dev/null +++ b/compiler/tests/integers/i32/min.leo @@ -0,0 +1,3 @@ +function main() -> i32 { + return -2147483648 +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/mod.rs b/compiler/tests/integers/i32/mod.rs new file mode 100644 index 0000000000..940379ad8d --- /dev/null +++ b/compiler/tests/integers/i32/mod.rs @@ -0,0 +1,105 @@ +use crate::{ + boolean::{output_expected_boolean, output_false, output_true}, + get_error, + get_output, + integers::{fail_integer, IntegerTester}, + parse_program, + EdwardsConstrainedValue, + EdwardsTestCompiler, +}; +use leo_compiler::{ConstrainedValue, Integer}; +use leo_gadgets::*; +use leo_inputs::types::{I32Type, IntegerType}; +use leo_types::InputValue; + +use snarkos_curves::edwards_bls12::Fq; +use snarkos_models::gadgets::{r1cs::TestConstraintSystem, utilities::alloc::AllocGadget}; + +fn output_expected_allocated(program: EdwardsTestCompiler, expected: Int32) { + let output = get_output(program); + + match output { + EdwardsConstrainedValue::Return(vec) => match vec.as_slice() { + [ConstrainedValue::Integer(Integer::I32(actual))] => assert_eq!(*actual, expected), + _ => panic!("program output unknown return value"), + }, + _ => panic!("program output unknown return value"), + } +} + +test_int!(TestI32, i32, IntegerType::I32Type(I32Type {}), Int32); + +#[test] +fn test_i32_min() { + TestI32::test_min(std::i32::MIN); +} + +#[test] +fn test_i32_max() { + TestI32::test_max(std::i32::MAX); +} + +#[test] +fn test_i32_input() { + TestI32::test_input(); +} + +#[test] +fn test_i32_add() { + TestI32::test_add(); +} + +#[test] +fn test_i32_sub() { + TestI32::test_sub(); +} + +#[test] +fn test_i32_mul() { + TestI32::test_mul(); +} + +#[test] +fn test_i32_div() { + TestI32::test_div(); +} + +#[test] +fn test_i32_pow() { + TestI32::test_pow(); +} + +#[test] +fn test_i32_eq() { + TestI32::test_eq(); +} + +#[test] +fn test_i32_ge() { + TestI32::test_ge(); +} + +#[test] +fn test_i32_gt() { + TestI32::test_gt(); +} + +#[test] +fn test_i32_le() { + TestI32::test_le(); +} + +#[test] +fn test_i32_lt() { + TestI32::test_lt(); +} + +#[test] +fn test_i32_assert_eq() { + TestI32::test_assert_eq(); +} + +#[test] +fn test_i32_ternary() { + TestI32::test_ternary(); +} diff --git a/compiler/tests/integers/i32/mul.leo b/compiler/tests/integers/i32/mul.leo new file mode 100644 index 0000000000..8ab0c36205 --- /dev/null +++ b/compiler/tests/integers/i32/mul.leo @@ -0,0 +1,3 @@ +function main(a: i32, b: i32) -> i32 { + return a * b +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/one.leo b/compiler/tests/integers/i32/one.leo new file mode 100644 index 0000000000..5ef3894d5e --- /dev/null +++ b/compiler/tests/integers/i32/one.leo @@ -0,0 +1,3 @@ +function main() -> i32 { + return 1 +} diff --git a/compiler/tests/integers/i32/pow.leo b/compiler/tests/integers/i32/pow.leo new file mode 100644 index 0000000000..790da91ead --- /dev/null +++ b/compiler/tests/integers/i32/pow.leo @@ -0,0 +1,3 @@ +function main(a: i32, b: i32) -> i32 { + return a ** b +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/sub.leo b/compiler/tests/integers/i32/sub.leo new file mode 100644 index 0000000000..c446484173 --- /dev/null +++ b/compiler/tests/integers/i32/sub.leo @@ -0,0 +1,3 @@ +function main(a: i32, b: i32) -> i32 { + return a - b +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/ternary.leo b/compiler/tests/integers/i32/ternary.leo new file mode 100644 index 0000000000..fbff679a00 --- /dev/null +++ b/compiler/tests/integers/i32/ternary.leo @@ -0,0 +1,3 @@ +function main(b: bool, x: i32, y: i32) -> i32 { + return if b ? x : y +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/zero.leo b/compiler/tests/integers/i32/zero.leo new file mode 100644 index 0000000000..53922fcf02 --- /dev/null +++ b/compiler/tests/integers/i32/zero.leo @@ -0,0 +1,3 @@ +function main() -> i32 { + return 0 +} diff --git a/compiler/tests/integers/i64/add.leo b/compiler/tests/integers/i64/add.leo new file mode 100644 index 0000000000..67d83b4193 --- /dev/null +++ b/compiler/tests/integers/i64/add.leo @@ -0,0 +1,3 @@ +function main(a: i64, b: i64) -> i64 { + return a + b +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/assert_eq.leo b/compiler/tests/integers/i64/assert_eq.leo new file mode 100644 index 0000000000..a9e7b44750 --- /dev/null +++ b/compiler/tests/integers/i64/assert_eq.leo @@ -0,0 +1,3 @@ +function main(a: i64, b: i64) { + assert_eq!(a, b); +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/div.leo b/compiler/tests/integers/i64/div.leo new file mode 100644 index 0000000000..e61e6f0850 --- /dev/null +++ b/compiler/tests/integers/i64/div.leo @@ -0,0 +1,3 @@ +function main(a: i64, b: i64) -> i64 { + return a / b +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/eq.leo b/compiler/tests/integers/i64/eq.leo new file mode 100644 index 0000000000..af2017d361 --- /dev/null +++ b/compiler/tests/integers/i64/eq.leo @@ -0,0 +1,3 @@ +function main(a: i64, b: i64) -> bool { + return a == b +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/ge.leo b/compiler/tests/integers/i64/ge.leo new file mode 100644 index 0000000000..cbe7fe0635 --- /dev/null +++ b/compiler/tests/integers/i64/ge.leo @@ -0,0 +1,3 @@ +function main(a: i64, b: i64) -> bool { + return a >= b +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/gt.leo b/compiler/tests/integers/i64/gt.leo new file mode 100644 index 0000000000..77286d5c82 --- /dev/null +++ b/compiler/tests/integers/i64/gt.leo @@ -0,0 +1,3 @@ +function main(a: i64, b: i64) -> bool { + return a > b +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/input.leo b/compiler/tests/integers/i64/input.leo new file mode 100644 index 0000000000..b9e90054a6 --- /dev/null +++ b/compiler/tests/integers/i64/input.leo @@ -0,0 +1,3 @@ +function main(x: i64) -> i64 { + return x +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/le.leo b/compiler/tests/integers/i64/le.leo new file mode 100644 index 0000000000..e2d31dcac5 --- /dev/null +++ b/compiler/tests/integers/i64/le.leo @@ -0,0 +1,3 @@ +function main(a: i64, b: i64) -> bool { + return a <= b +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/lt.leo b/compiler/tests/integers/i64/lt.leo new file mode 100644 index 0000000000..c46123fc42 --- /dev/null +++ b/compiler/tests/integers/i64/lt.leo @@ -0,0 +1,3 @@ +function main(a: i64, b: i64) -> bool { + return a < b +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/max.leo b/compiler/tests/integers/i64/max.leo new file mode 100644 index 0000000000..0173b80e94 --- /dev/null +++ b/compiler/tests/integers/i64/max.leo @@ -0,0 +1,3 @@ +function main() -> i64 { + return 9223372036854775807 +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/min.leo b/compiler/tests/integers/i64/min.leo new file mode 100644 index 0000000000..3a1817a736 --- /dev/null +++ b/compiler/tests/integers/i64/min.leo @@ -0,0 +1,3 @@ +function main() -> i64 { + return -9223372036854775808 +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/mod.rs b/compiler/tests/integers/i64/mod.rs new file mode 100644 index 0000000000..e0774f4a85 --- /dev/null +++ b/compiler/tests/integers/i64/mod.rs @@ -0,0 +1,105 @@ +use crate::{ + boolean::{output_expected_boolean, output_false, output_true}, + get_error, + get_output, + integers::{fail_integer, IntegerTester}, + parse_program, + EdwardsConstrainedValue, + EdwardsTestCompiler, +}; +use leo_compiler::{ConstrainedValue, Integer}; +use leo_gadgets::*; +use leo_inputs::types::{I64Type, IntegerType}; +use leo_types::InputValue; + +use snarkos_curves::edwards_bls12::Fq; +use snarkos_models::gadgets::{r1cs::TestConstraintSystem, utilities::alloc::AllocGadget}; + +fn output_expected_allocated(program: EdwardsTestCompiler, expected: Int64) { + let output = get_output(program); + + match output { + EdwardsConstrainedValue::Return(vec) => match vec.as_slice() { + [ConstrainedValue::Integer(Integer::I64(actual))] => assert_eq!(*actual, expected), + _ => panic!("program output unknown return value"), + }, + _ => panic!("program output unknown return value"), + } +} + +test_int!(TestI64, i64, IntegerType::I64Type(I64Type {}), Int64); + +#[test] +fn test_i64_min() { + TestI64::test_min(std::i64::MIN); +} + +#[test] +fn test_i64_max() { + TestI64::test_max(std::i64::MAX); +} + +#[test] +fn test_i64_input() { + TestI64::test_input(); +} + +#[test] +fn test_i64_add() { + TestI64::test_add(); +} + +#[test] +fn test_i64_sub() { + TestI64::test_sub(); +} + +#[test] +fn test_i64_mul() { + TestI64::test_mul(); +} + +#[test] +fn test_i64_div() { + TestI64::test_div(); +} + +#[test] +fn test_i64_pow() { + TestI64::test_pow(); +} + +#[test] +fn test_i64_eq() { + TestI64::test_eq(); +} + +#[test] +fn test_i64_ge() { + TestI64::test_ge(); +} + +#[test] +fn test_i64_gt() { + TestI64::test_gt(); +} + +#[test] +fn test_i64_le() { + TestI64::test_le(); +} + +#[test] +fn test_i64_lt() { + TestI64::test_lt(); +} + +#[test] +fn test_i64_assert_eq() { + TestI64::test_assert_eq(); +} + +#[test] +fn test_i64_ternary() { + TestI64::test_ternary(); +} diff --git a/compiler/tests/integers/i64/mul.leo b/compiler/tests/integers/i64/mul.leo new file mode 100644 index 0000000000..f9d415009b --- /dev/null +++ b/compiler/tests/integers/i64/mul.leo @@ -0,0 +1,3 @@ +function main(a: i64, b: i64) -> i64 { + return a * b +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/one.leo b/compiler/tests/integers/i64/one.leo new file mode 100644 index 0000000000..c3fd8abc72 --- /dev/null +++ b/compiler/tests/integers/i64/one.leo @@ -0,0 +1,3 @@ +function main() -> i64 { + return 1 +} diff --git a/compiler/tests/integers/i64/pow.leo b/compiler/tests/integers/i64/pow.leo new file mode 100644 index 0000000000..efad660c04 --- /dev/null +++ b/compiler/tests/integers/i64/pow.leo @@ -0,0 +1,3 @@ +function main(a: i64, b: i64) -> i64 { + return a ** b +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/sub.leo b/compiler/tests/integers/i64/sub.leo new file mode 100644 index 0000000000..bc5be06b7a --- /dev/null +++ b/compiler/tests/integers/i64/sub.leo @@ -0,0 +1,3 @@ +function main(a: i64, b: i64) -> i64 { + return a - b +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/ternary.leo b/compiler/tests/integers/i64/ternary.leo new file mode 100644 index 0000000000..dc7bf1f81e --- /dev/null +++ b/compiler/tests/integers/i64/ternary.leo @@ -0,0 +1,3 @@ +function main(b: bool, x: i64, y: i64) -> i64 { + return if b ? x : y +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/zero.leo b/compiler/tests/integers/i64/zero.leo new file mode 100644 index 0000000000..ce0a3bd9c2 --- /dev/null +++ b/compiler/tests/integers/i64/zero.leo @@ -0,0 +1,3 @@ +function main() -> i64 { + return 0 +} diff --git a/compiler/tests/integers/i8/add.leo b/compiler/tests/integers/i8/add.leo new file mode 100644 index 0000000000..47cd676483 --- /dev/null +++ b/compiler/tests/integers/i8/add.leo @@ -0,0 +1,3 @@ +function main(a: i8, b: i8) -> i8 { + return a + b +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/assert_eq.leo b/compiler/tests/integers/i8/assert_eq.leo new file mode 100644 index 0000000000..c397ca8c07 --- /dev/null +++ b/compiler/tests/integers/i8/assert_eq.leo @@ -0,0 +1,3 @@ +function main(a: i8, b: i8) { + assert_eq!(a, b); +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/div.leo b/compiler/tests/integers/i8/div.leo new file mode 100644 index 0000000000..7382b985e9 --- /dev/null +++ b/compiler/tests/integers/i8/div.leo @@ -0,0 +1,3 @@ +function main(a: i8, b: i8) -> i8 { + return a / b +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/eq.leo b/compiler/tests/integers/i8/eq.leo new file mode 100644 index 0000000000..2b8c3c11bd --- /dev/null +++ b/compiler/tests/integers/i8/eq.leo @@ -0,0 +1,3 @@ +function main(a: i8, b: i8) -> bool { + return a == b +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/ge.leo b/compiler/tests/integers/i8/ge.leo new file mode 100644 index 0000000000..69d9808a09 --- /dev/null +++ b/compiler/tests/integers/i8/ge.leo @@ -0,0 +1,3 @@ +function main(a: i8, b: i8) -> bool { + return a >= b +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/gt.leo b/compiler/tests/integers/i8/gt.leo new file mode 100644 index 0000000000..6346b285cd --- /dev/null +++ b/compiler/tests/integers/i8/gt.leo @@ -0,0 +1,3 @@ +function main(a: i8, b: i8) -> bool { + return a > b +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/input.leo b/compiler/tests/integers/i8/input.leo new file mode 100644 index 0000000000..ae50705338 --- /dev/null +++ b/compiler/tests/integers/i8/input.leo @@ -0,0 +1,3 @@ +function main(x: i8) -> i8 { + return x +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/le.leo b/compiler/tests/integers/i8/le.leo new file mode 100644 index 0000000000..791e64d793 --- /dev/null +++ b/compiler/tests/integers/i8/le.leo @@ -0,0 +1,3 @@ +function main(a: i8, b: i8) -> bool { + return a <= b +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/lt.leo b/compiler/tests/integers/i8/lt.leo new file mode 100644 index 0000000000..00c6e61324 --- /dev/null +++ b/compiler/tests/integers/i8/lt.leo @@ -0,0 +1,3 @@ +function main(a: i8, b: i8) -> bool { + return a < b +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/max.leo b/compiler/tests/integers/i8/max.leo new file mode 100644 index 0000000000..ed57f26a33 --- /dev/null +++ b/compiler/tests/integers/i8/max.leo @@ -0,0 +1,3 @@ +function main() -> i8 { + return 127 +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/min.leo b/compiler/tests/integers/i8/min.leo new file mode 100644 index 0000000000..d334e0ad4c --- /dev/null +++ b/compiler/tests/integers/i8/min.leo @@ -0,0 +1,3 @@ +function main() -> i8 { + return -128 +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/mod.rs b/compiler/tests/integers/i8/mod.rs new file mode 100644 index 0000000000..94c1dde76a --- /dev/null +++ b/compiler/tests/integers/i8/mod.rs @@ -0,0 +1,105 @@ +use crate::{ + boolean::{output_expected_boolean, output_false, output_true}, + get_error, + get_output, + integers::{fail_integer, IntegerTester}, + parse_program, + EdwardsConstrainedValue, + EdwardsTestCompiler, +}; +use leo_compiler::{ConstrainedValue, Integer}; +use leo_gadgets::*; +use leo_inputs::types::{I8Type, IntegerType}; +use leo_types::InputValue; + +use snarkos_curves::edwards_bls12::Fq; +use snarkos_models::gadgets::{r1cs::TestConstraintSystem, utilities::alloc::AllocGadget}; + +fn output_expected_allocated(program: EdwardsTestCompiler, expected: Int8) { + let output = get_output(program); + + match output { + EdwardsConstrainedValue::Return(vec) => match vec.as_slice() { + [ConstrainedValue::Integer(Integer::I8(actual))] => assert_eq!(*actual, expected), + _ => panic!("program output unknown return value"), + }, + _ => panic!("program output unknown return value"), + } +} + +test_int!(TestI8, i8, IntegerType::I8Type(I8Type {}), Int8); + +#[test] +fn test_i8_min() { + TestI8::test_min(std::i8::MIN); +} + +#[test] +fn test_i8_max() { + TestI8::test_max(std::i8::MAX); +} + +#[test] +fn test_i8_input() { + TestI8::test_input(); +} + +#[test] +fn test_i8_add() { + TestI8::test_add(); +} + +#[test] +fn test_i8_sub() { + TestI8::test_sub(); +} + +#[test] +fn test_i8_mul() { + TestI8::test_mul(); +} + +#[test] +fn test_i8_div() { + TestI8::test_div(); +} + +#[test] +fn test_i8_pow() { + TestI8::test_pow(); +} + +#[test] +fn test_i8_eq() { + TestI8::test_eq(); +} + +#[test] +fn test_i8_ge() { + TestI8::test_ge(); +} + +#[test] +fn test_i8_gt() { + TestI8::test_gt(); +} + +#[test] +fn test_i8_le() { + TestI8::test_le(); +} + +#[test] +fn test_i8_lt() { + TestI8::test_lt(); +} + +#[test] +fn test_i8_assert_eq() { + TestI8::test_assert_eq(); +} + +#[test] +fn test_i8_ternary() { + TestI8::test_ternary(); +} diff --git a/compiler/tests/integers/i8/mul.leo b/compiler/tests/integers/i8/mul.leo new file mode 100644 index 0000000000..88c4fa5b5d --- /dev/null +++ b/compiler/tests/integers/i8/mul.leo @@ -0,0 +1,3 @@ +function main(a: i8, b: i8) -> i8 { + return a * b +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/one.leo b/compiler/tests/integers/i8/one.leo new file mode 100644 index 0000000000..2e0ffefa27 --- /dev/null +++ b/compiler/tests/integers/i8/one.leo @@ -0,0 +1,3 @@ +function main() -> i8 { + return 1 +} diff --git a/compiler/tests/integers/i8/pow.leo b/compiler/tests/integers/i8/pow.leo new file mode 100644 index 0000000000..68837dda70 --- /dev/null +++ b/compiler/tests/integers/i8/pow.leo @@ -0,0 +1,3 @@ +function main(a: i8, b: i8) -> i8 { + return a ** b +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/sub.leo b/compiler/tests/integers/i8/sub.leo new file mode 100644 index 0000000000..234a4f4fee --- /dev/null +++ b/compiler/tests/integers/i8/sub.leo @@ -0,0 +1,3 @@ +function main(a: i8, b: i8) -> i8 { + return a - b +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/ternary.leo b/compiler/tests/integers/i8/ternary.leo new file mode 100644 index 0000000000..68bcbd1a03 --- /dev/null +++ b/compiler/tests/integers/i8/ternary.leo @@ -0,0 +1,3 @@ +function main(b: bool, x: i8, y: i8) -> i8 { + return if b ? x : y +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/zero.leo b/compiler/tests/integers/i8/zero.leo new file mode 100644 index 0000000000..d58befa8b9 --- /dev/null +++ b/compiler/tests/integers/i8/zero.leo @@ -0,0 +1,3 @@ +function main() -> i8 { + return 0 +} diff --git a/compiler/tests/integers/int_macro.rs b/compiler/tests/integers/int_macro.rs new file mode 100644 index 0000000000..0c40e783ee --- /dev/null +++ b/compiler/tests/integers/int_macro.rs @@ -0,0 +1,407 @@ +macro_rules! test_int { + ($name: ident, $type_: ty, $integer_type: expr, $gadget: ty) => { + pub struct $name {} + + impl $name { + fn test_min(min: $type_) { + let min_allocated = <$gadget>::constant(min); + + let bytes = include_bytes!("min.leo"); + let program = parse_program(bytes).unwrap(); + + output_expected_allocated(program, min_allocated); + } + + fn test_max(max: $type_) { + let max_allocated = <$gadget>::constant(max); + + let bytes = include_bytes!("max.leo"); + let program = parse_program(bytes).unwrap(); + + output_expected_allocated(program, max_allocated); + } + } + + impl IntegerTester for $name { + fn test_input() { + // valid input + let num: $type_ = rand::random(); + let expected = <$gadget>::constant(num); + + let bytes = include_bytes!("input.leo"); + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![Some(InputValue::Integer($integer_type, num.to_string()))]); + + output_expected_allocated(program, expected); + + // invalid input + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![Some(InputValue::Boolean(true))]); + fail_integer(program); + + // None input + let mut program = parse_program(bytes).unwrap(); + program.set_inputs(vec![None]); + fail_integer(program); + } + + fn test_add() { + for _ in 0..10 { + let r1: $type_ = rand::random(); + let r2: $type_ = rand::random(); + + let sum = match r1.checked_add(r2) { + Some(valid) => valid, + None => continue, + }; + + let cs = TestConstraintSystem::::new(); + let sum_allocated = <$gadget>::alloc(cs, || Ok(sum)).unwrap(); + + let bytes = include_bytes!("add.leo"); + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), + ]); + + output_expected_allocated(program, sum_allocated); + } + } + + fn test_sub() { + for _ in 0..10 { + let r1: $type_ = rand::random(); + let r2: $type_ = rand::random(); + + if r2.checked_neg().is_none() { + continue; + } + + let difference = match r1.checked_sub(r2) { + Some(valid) => valid, + None => continue, + }; + + let cs = TestConstraintSystem::::new(); + let difference_allocated = <$gadget>::alloc(cs, || Ok(difference)).unwrap(); + + let bytes = include_bytes!("sub.leo"); + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), + ]); + + output_expected_allocated(program, difference_allocated); + } + } + + fn test_mul() { + for _ in 0..10 { + let r1: $type_ = rand::random(); + let r2: $type_ = rand::random(); + + let product = match r1.checked_mul(r2) { + Some(valid) => valid, + None => continue, + }; + + let cs = TestConstraintSystem::::new(); + let product_allocated = <$gadget>::alloc(cs, || Ok(product)).unwrap(); + + let bytes = include_bytes!("mul.leo"); + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), + ]); + + output_expected_allocated(program, product_allocated); + } + } + + fn test_div() { + // for _ in 0..10 {// these loops take an excessive amount of time + let r1: $type_ = rand::random(); + let r2: $type_ = rand::random(); + + let bytes = include_bytes!("div.leo"); + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), + ]); + + // expect an error when dividing by zero + if r2 == 0 { + let _err = get_error(program); + } else { + let cs = TestConstraintSystem::::new(); + + let quotient = match r1.checked_div(r2) { + Some(valid) => valid, + None => return, + }; + let quotient_allocated = <$gadget>::alloc(cs, || Ok(quotient)).unwrap(); + + output_expected_allocated(program, quotient_allocated); + } + // } + } + + fn test_pow() { + // for _ in 0..10 {// these loops take an excessive amount of time + let r1: $type_ = rand::random(); + let r2: $type_ = rand::random(); + let r2 = r2 as u32; // we cast to u32 here because of rust pow() requirements + + let result = match r1.checked_pow(r2) { + Some(valid) => valid, + None => return, + }; + + let cs = TestConstraintSystem::::new(); + let result_allocated = <$gadget>::alloc(cs, || Ok(result)).unwrap(); + + let bytes = include_bytes!("pow.leo"); + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), + ]); + + output_expected_allocated(program, result_allocated); + // } + } + + fn test_eq() { + for _ in 0..10 { + let r1: $type_ = rand::random(); + + // test equal + let bytes = include_bytes!("eq.leo"); + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r1.to_string())), + ]); + + output_true(program); + + // test not equal + let r2: $type_ = rand::random(); + + let result = r1.eq(&r2); + + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), + ]); + + output_expected_boolean(program, result); + } + } + + fn test_ge() { + for _ in 0..10 { + let r1: $type_ = rand::random(); + + // test equal + let bytes = include_bytes!("ge.leo"); + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r1.to_string())), + ]); + + output_true(program); + + // test not equal + let r2: $type_ = rand::random(); + + let result = r1.ge(&r2); + + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), + ]); + + output_expected_boolean(program, result); + } + } + + fn test_gt() { + for _ in 0..10 { + let r1: $type_ = rand::random(); + + // test equal + let bytes = include_bytes!("gt.leo"); + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r1.to_string())), + ]); + + output_false(program); + + // test not equal + let r2: $type_ = rand::random(); + + let result = r1.gt(&r2); + + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), + ]); + + output_expected_boolean(program, result); + } + } + + fn test_le() { + for _ in 0..10 { + let r1: $type_ = rand::random(); + + // test equal + let bytes = include_bytes!("le.leo"); + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r1.to_string())), + ]); + + output_true(program); + + // test not equal + let r2: $type_ = rand::random(); + + let result = r1.le(&r2); + + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), + ]); + + output_expected_boolean(program, result); + } + } + + fn test_lt() { + for _ in 0..10 { + let r1: $type_ = rand::random(); + + // test equal + let bytes = include_bytes!("lt.leo"); + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r1.to_string())), + ]); + + output_false(program); + + // test not equal + let r2: $type_ = rand::random(); + + let result = r1.lt(&r2); + + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), + ]); + + output_expected_boolean(program, result); + } + } + + fn test_assert_eq() { + for _ in 0..10 { + let r1: $type_ = rand::random(); + + // test equal + let bytes = include_bytes!("assert_eq.leo"); + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r1.to_string())), + ]); + + let _ = get_output(program); + + // test not equal + let r2: $type_ = rand::random(); + + if r1 == r2 { + continue; + } + + let mut program = parse_program(bytes).unwrap(); + + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), + ]); + + let mut cs = TestConstraintSystem::::new(); + let _ = program.compile_constraints(&mut cs).unwrap(); + assert!(!cs.is_satisfied()); + } + } + + fn test_ternary() { + let r1: $type_ = rand::random(); + let r2: $type_ = rand::random(); + + let g1 = <$gadget>::constant(r1); + let g2 = <$gadget>::constant(r2); + + let bytes = include_bytes!("ternary.leo"); + let mut program_1 = parse_program(bytes).unwrap(); + + let mut program_2 = program_1.clone(); + + // true -> field 1 + program_1.set_inputs(vec![ + Some(InputValue::Boolean(true)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), + ]); + + output_expected_allocated(program_1, g1); + + // false -> field 2 + program_2.set_inputs(vec![ + Some(InputValue::Boolean(false)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), + ]); + + output_expected_allocated(program_2, g2); + } + } + }; +} diff --git a/compiler/tests/integers/integer_tester.rs b/compiler/tests/integers/integer_tester.rs new file mode 100644 index 0000000000..700edb0bbc --- /dev/null +++ b/compiler/tests/integers/integer_tester.rs @@ -0,0 +1,50 @@ +use crate::{get_error, EdwardsTestCompiler}; +use leo_compiler::errors::{CompilerError, FunctionError, IntegerError}; + +pub trait IntegerTester { + /// Tests use of the integer in a function input + fn test_input(); + + /// Tests a wrapping addition + fn test_add(); + + /// Tests a wrapping subtraction + fn test_sub(); + + /// Tests a wrapping multiplication + fn test_mul(); + + /// Tests a non-wrapping division + fn test_div(); + + /// Tests a wrapping exponentiation + fn test_pow(); + + /// Tests == evaluation + fn test_eq(); + + /// Tests >= evaluation + fn test_ge(); + + /// Tests > evaluation + fn test_gt(); + + /// Tests <= evaluation + fn test_le(); + + /// Tests < evaluation + fn test_lt(); + + /// Test assert equals constraint keyword + fn test_assert_eq(); + + /// Test ternary if bool ? num_1 : num_2; + fn test_ternary(); +} + +pub(crate) fn fail_integer(program: EdwardsTestCompiler) { + match get_error(program) { + CompilerError::FunctionError(FunctionError::IntegerError(IntegerError::Error(_string))) => {} + error => panic!("Expected invalid boolean error, got {}", error), + } +} diff --git a/compiler/tests/integers/mod.rs b/compiler/tests/integers/mod.rs index a863150758..2abbeacf2e 100644 --- a/compiler/tests/integers/mod.rs +++ b/compiler/tests/integers/mod.rs @@ -1,56 +1,11 @@ #[macro_use] -pub mod macros; +pub mod int_macro; -use crate::{get_error, EdwardsTestCompiler}; -use leo_compiler::errors::{CompilerError, FunctionError, IntegerError}; +#[macro_use] +pub mod uint_macro; -pub trait IntegerTester { - /// Tests use of the integer in a function input - fn test_input(); - - /// Tests a wrapping addition - fn test_add(); - - /// Tests a wrapping subtraction - fn test_sub(); - - /// Tests a wrapping multiplication - fn test_mul(); - - /// Tests a non-wrapping division - fn test_div(); - - /// Tests a wrapping exponentiation - fn test_pow(); - - /// Tests == evaluation - fn test_eq(); - - /// Tests >= evaluation - fn test_ge(); - - /// Tests > evaluation - fn test_gt(); - - /// Tests <= evaluation - fn test_le(); - - /// Tests < evaluation - fn test_lt(); - - /// Test assert equals constraint keyword - fn test_assert_eq(); - - /// Test ternary if bool ? num_1 : num_2; - fn test_ternary(); -} - -pub(crate) fn fail_integer(program: EdwardsTestCompiler) { - match get_error(program) { - CompilerError::FunctionError(FunctionError::IntegerError(IntegerError::Error(_string))) => {} - error => panic!("Expected invalid boolean error, got {}", error), - } -} +pub mod integer_tester; +pub use self::integer_tester::*; // must be below macro definitions! pub mod u128; @@ -58,3 +13,9 @@ pub mod u16; pub mod u32; pub mod u64; pub mod u8; + +pub mod i128; +pub mod i16; +pub mod i32; +pub mod i64; +pub mod i8; diff --git a/compiler/tests/integers/u128/add.leo b/compiler/tests/integers/u128/add.leo index 276fa2acd5..7f35c07751 100644 --- a/compiler/tests/integers/u128/add.leo +++ b/compiler/tests/integers/u128/add.leo @@ -1,3 +1,3 @@ function main(a: u128, b: u128) -> u128 { - return a + b + return a + b } \ No newline at end of file diff --git a/compiler/tests/integers/u128/assert_eq.leo b/compiler/tests/integers/u128/assert_eq.leo index 5648ca37d3..9ee2ff0f12 100644 --- a/compiler/tests/integers/u128/assert_eq.leo +++ b/compiler/tests/integers/u128/assert_eq.leo @@ -1,3 +1,3 @@ function main(a: u128, b: u128) { - assert_eq!(a, b); + assert_eq!(a, b); } \ No newline at end of file diff --git a/compiler/tests/integers/u128/div.leo b/compiler/tests/integers/u128/div.leo index b016441bb4..a9c65e885c 100644 --- a/compiler/tests/integers/u128/div.leo +++ b/compiler/tests/integers/u128/div.leo @@ -1,3 +1,3 @@ function main(a: u128, b: u128) -> u128 { - return a / b + return a / b } \ No newline at end of file diff --git a/compiler/tests/integers/u128/eq.leo b/compiler/tests/integers/u128/eq.leo index 3d11fb9a62..c1fd10e66b 100644 --- a/compiler/tests/integers/u128/eq.leo +++ b/compiler/tests/integers/u128/eq.leo @@ -1,3 +1,3 @@ function main(a: u128, b: u128) -> bool { - return a == b + return a == b } \ No newline at end of file diff --git a/compiler/tests/integers/u128/ge.leo b/compiler/tests/integers/u128/ge.leo index 8e5b955ca4..8488e49b55 100644 --- a/compiler/tests/integers/u128/ge.leo +++ b/compiler/tests/integers/u128/ge.leo @@ -1,3 +1,3 @@ function main(a: u128, b: u128) -> bool { - return a >= b + return a >= b } \ No newline at end of file diff --git a/compiler/tests/integers/u128/gt.leo b/compiler/tests/integers/u128/gt.leo index 2bb088ae4c..d67b008595 100644 --- a/compiler/tests/integers/u128/gt.leo +++ b/compiler/tests/integers/u128/gt.leo @@ -1,3 +1,3 @@ function main(a: u128, b: u128) -> bool { - return a > b + return a > b } \ No newline at end of file diff --git a/compiler/tests/integers/u128/input.leo b/compiler/tests/integers/u128/input.leo index 0ca95d5844..4424cccda9 100644 --- a/compiler/tests/integers/u128/input.leo +++ b/compiler/tests/integers/u128/input.leo @@ -1,3 +1,3 @@ function main(x: u128) -> u128 { - return x + return x } \ No newline at end of file diff --git a/compiler/tests/integers/u128/le.leo b/compiler/tests/integers/u128/le.leo index e987cd22ac..cfc4fb9d7c 100644 --- a/compiler/tests/integers/u128/le.leo +++ b/compiler/tests/integers/u128/le.leo @@ -1,3 +1,3 @@ function main(a: u128, b: u128) -> bool { - return a <= b + return a <= b } \ No newline at end of file diff --git a/compiler/tests/integers/u128/lt.leo b/compiler/tests/integers/u128/lt.leo index 44c7682712..35fdd5dd6b 100644 --- a/compiler/tests/integers/u128/lt.leo +++ b/compiler/tests/integers/u128/lt.leo @@ -1,3 +1,3 @@ function main(a: u128, b: u128) -> bool { - return a < b + return a < b } \ No newline at end of file diff --git a/compiler/tests/integers/u128/max.leo b/compiler/tests/integers/u128/max.leo index 4e80deb7ff..91965c2bc4 100644 --- a/compiler/tests/integers/u128/max.leo +++ b/compiler/tests/integers/u128/max.leo @@ -1,3 +1,3 @@ function main() -> u128 { - return 340282366920938463463374607431768211455 + return 340282366920938463463374607431768211455 } \ No newline at end of file diff --git a/compiler/tests/integers/u128/min.leo b/compiler/tests/integers/u128/min.leo index 871132de06..cd626f2125 100644 --- a/compiler/tests/integers/u128/min.leo +++ b/compiler/tests/integers/u128/min.leo @@ -1,3 +1,3 @@ function main() -> u128 { - return 0 + return 0 } \ No newline at end of file diff --git a/compiler/tests/integers/u128/mod.rs b/compiler/tests/integers/u128/mod.rs index 800208b945..e1a8470c60 100644 --- a/compiler/tests/integers/u128/mod.rs +++ b/compiler/tests/integers/u128/mod.rs @@ -28,29 +28,80 @@ fn output_expected_allocated(program: EdwardsTestCompiler, expected: UInt128) { _ => panic!("program output unknown return value"), } } +test_uint!(TestU128, u128, IntegerType::U128Type(U128Type {}), UInt128); #[test] -#[ignore] // temporarily ignore memory expensive tests for travis -fn test_u128() { - test_uint!(TestU128, u128, IntegerType::U128Type(U128Type {}), UInt128); - +fn test_u128_min() { TestU128::test_min(std::u128::MIN); +} + +#[test] +fn test_u128_max() { TestU128::test_max(std::u128::MAX); +} +#[test] +fn test_u128_input() { TestU128::test_input(); +} +#[test] +fn test_u128_add() { TestU128::test_add(); - // TestU128::test_sub(); //Todo: Catch subtraction overflow error in gadget +} + +#[test] +fn test_u128_sub() { + TestU128::test_sub(); +} + +#[test] // this test take ~1 min +fn test_u128_mul() { TestU128::test_mul(); +} + +#[test] // this test takes ~30 sec +fn test_u128_div() { TestU128::test_div(); - // TestU128::test_pow(); // takes about 10 minutes +} +#[test] +#[ignore] // this test takes ~10 mins +fn test_u128_pow() { + TestU128::test_pow(); +} + +#[test] +fn test_u128_eq() { TestU128::test_eq(); - TestU128::test_ge(); - TestU128::test_gt(); - TestU128::test_le(); - TestU128::test_gt(); +} +#[test] +fn test_u128_ge() { + TestU128::test_ge(); +} + +#[test] +fn test_u128_gt() { + TestU128::test_gt(); +} + +#[test] +fn test_u128_le() { + TestU128::test_le(); +} + +#[test] +fn test_u128_lt() { + TestU128::test_lt(); +} + +#[test] +fn test_u128_assert_eq() { TestU128::test_assert_eq(); +} + +#[test] +fn test_u128_ternary() { TestU128::test_ternary(); } diff --git a/compiler/tests/integers/u128/mul.leo b/compiler/tests/integers/u128/mul.leo index f611cc3e56..69f5787c02 100644 --- a/compiler/tests/integers/u128/mul.leo +++ b/compiler/tests/integers/u128/mul.leo @@ -1,3 +1,3 @@ function main(a: u128, b: u128) -> u128 { - return a * b + return a * b } \ No newline at end of file diff --git a/compiler/tests/integers/u128/pow.leo b/compiler/tests/integers/u128/pow.leo index ce84e423f6..b18fad1df3 100644 --- a/compiler/tests/integers/u128/pow.leo +++ b/compiler/tests/integers/u128/pow.leo @@ -1,3 +1,3 @@ function main(a: u128, b: u128) -> u128 { - return a ** b + return a ** b } \ No newline at end of file diff --git a/compiler/tests/integers/u128/sub.leo b/compiler/tests/integers/u128/sub.leo index bc9ea56a86..408ff755ff 100644 --- a/compiler/tests/integers/u128/sub.leo +++ b/compiler/tests/integers/u128/sub.leo @@ -1,3 +1,3 @@ function main(a: u128, b: u128) -> u128 { - return a - b + return a - b } \ No newline at end of file diff --git a/compiler/tests/integers/u128/ternary.leo b/compiler/tests/integers/u128/ternary.leo index 4a41327776..2ebc800648 100644 --- a/compiler/tests/integers/u128/ternary.leo +++ b/compiler/tests/integers/u128/ternary.leo @@ -1,3 +1,3 @@ function main(b: bool, x: u128, y: u128) -> u128 { - return if b ? x : y + return if b ? x : y } \ No newline at end of file diff --git a/compiler/tests/integers/u16/add.leo b/compiler/tests/integers/u16/add.leo index eca13e6b46..93b807afda 100644 --- a/compiler/tests/integers/u16/add.leo +++ b/compiler/tests/integers/u16/add.leo @@ -1,3 +1,3 @@ function main(a: u16, b: u16) -> u16 { - return a + b + return a + b } \ No newline at end of file diff --git a/compiler/tests/integers/u16/assert_eq.leo b/compiler/tests/integers/u16/assert_eq.leo index 719cfe789c..38f850139c 100644 --- a/compiler/tests/integers/u16/assert_eq.leo +++ b/compiler/tests/integers/u16/assert_eq.leo @@ -1,3 +1,3 @@ function main(a: u16, b: u16) { - assert_eq!(a, b); + assert_eq!(a, b); } \ No newline at end of file diff --git a/compiler/tests/integers/u16/div.leo b/compiler/tests/integers/u16/div.leo index 1f210c1373..1290856935 100644 --- a/compiler/tests/integers/u16/div.leo +++ b/compiler/tests/integers/u16/div.leo @@ -1,3 +1,3 @@ function main(a: u16, b: u16) -> u16 { - return a / b + return a / b } \ No newline at end of file diff --git a/compiler/tests/integers/u16/eq.leo b/compiler/tests/integers/u16/eq.leo index 2709c5f52b..bb643aca0b 100644 --- a/compiler/tests/integers/u16/eq.leo +++ b/compiler/tests/integers/u16/eq.leo @@ -1,3 +1,3 @@ function main(a: u16, b: u16) -> bool { - return a == b + return a == b } \ No newline at end of file diff --git a/compiler/tests/integers/u16/ge.leo b/compiler/tests/integers/u16/ge.leo index 915cf30ee3..4f4d2b8a79 100644 --- a/compiler/tests/integers/u16/ge.leo +++ b/compiler/tests/integers/u16/ge.leo @@ -1,3 +1,3 @@ function main(a: u16, b: u16) -> bool { - return a >= b + return a >= b } \ No newline at end of file diff --git a/compiler/tests/integers/u16/gt.leo b/compiler/tests/integers/u16/gt.leo index c092d3ef1b..4c234b4c9a 100644 --- a/compiler/tests/integers/u16/gt.leo +++ b/compiler/tests/integers/u16/gt.leo @@ -1,3 +1,3 @@ function main(a: u16, b: u16) -> bool { - return a > b + return a > b } \ No newline at end of file diff --git a/compiler/tests/integers/u16/input.leo b/compiler/tests/integers/u16/input.leo index f2a19fd7ee..2a4801074f 100644 --- a/compiler/tests/integers/u16/input.leo +++ b/compiler/tests/integers/u16/input.leo @@ -1,3 +1,3 @@ function main(x: u16) -> u16 { - return x + return x } \ No newline at end of file diff --git a/compiler/tests/integers/u16/le.leo b/compiler/tests/integers/u16/le.leo index 98a29babb0..b463e929a4 100644 --- a/compiler/tests/integers/u16/le.leo +++ b/compiler/tests/integers/u16/le.leo @@ -1,3 +1,3 @@ function main(a: u16, b: u16) -> bool { - return a <= b + return a <= b } \ No newline at end of file diff --git a/compiler/tests/integers/u16/lt.leo b/compiler/tests/integers/u16/lt.leo index cb59ad5fda..05cb9b54b5 100644 --- a/compiler/tests/integers/u16/lt.leo +++ b/compiler/tests/integers/u16/lt.leo @@ -1,3 +1,3 @@ function main(a: u16, b: u16) -> bool { - return a < b + return a < b } \ No newline at end of file diff --git a/compiler/tests/integers/u16/max.leo b/compiler/tests/integers/u16/max.leo index a713f34abe..2e87cbac0e 100644 --- a/compiler/tests/integers/u16/max.leo +++ b/compiler/tests/integers/u16/max.leo @@ -1,3 +1,3 @@ function main() -> u16 { - return 65535 + return 65535 } \ No newline at end of file diff --git a/compiler/tests/integers/u16/min.leo b/compiler/tests/integers/u16/min.leo index 41dbdf8422..d3f9ed6824 100644 --- a/compiler/tests/integers/u16/min.leo +++ b/compiler/tests/integers/u16/min.leo @@ -1,3 +1,3 @@ function main() -> u16 { - return 0 + return 0 } \ No newline at end of file diff --git a/compiler/tests/integers/u16/mod.rs b/compiler/tests/integers/u16/mod.rs index 1c231abfcf..15534974e3 100644 --- a/compiler/tests/integers/u16/mod.rs +++ b/compiler/tests/integers/u16/mod.rs @@ -29,27 +29,79 @@ fn output_expected_allocated(program: EdwardsTestCompiler, expected: UInt16) { } } +test_uint!(TestU16, u16, IntegerType::U16Type(U16Type {}), UInt16); + #[test] -fn test_u16() { - test_uint!(Testu16, u16, IntegerType::U16Type(U16Type {}), UInt16); - - Testu16::test_min(std::u16::MIN); - Testu16::test_max(std::u16::MAX); - - Testu16::test_input(); - - Testu16::test_add(); - // Testu16::test_sub(); //Todo: Catch subtraction overflow error in gadget - Testu16::test_mul(); - Testu16::test_div(); - Testu16::test_pow(); - - Testu16::test_eq(); - Testu16::test_ge(); - Testu16::test_gt(); - Testu16::test_le(); - Testu16::test_gt(); - - Testu16::test_assert_eq(); - Testu16::test_ternary(); +fn test_u16_min() { + TestU16::test_min(std::u16::MIN); +} + +#[test] +fn test_u16_max() { + TestU16::test_max(std::u16::MAX); +} + +#[test] +fn test_u16_input() { + TestU16::test_input(); +} + +#[test] +fn test_u16_add() { + TestU16::test_add(); +} + +#[test] +fn test_u16_sub() { + TestU16::test_sub(); +} + +#[test] +fn test_u16_mul() { + TestU16::test_mul(); +} + +#[test] +fn test_u16_div() { + TestU16::test_div(); +} + +#[test] +fn test_u16_pow() { + TestU16::test_pow(); +} + +#[test] +fn test_u16_eq() { + TestU16::test_eq(); +} + +#[test] +fn test_u16_ge() { + TestU16::test_ge(); +} + +#[test] +fn test_u16_gt() { + TestU16::test_gt(); +} + +#[test] +fn test_u16_le() { + TestU16::test_le(); +} + +#[test] +fn test_u16_lt() { + TestU16::test_lt(); +} + +#[test] +fn test_u16_assert_eq() { + TestU16::test_assert_eq(); +} + +#[test] +fn test_u16_ternary() { + TestU16::test_ternary(); } diff --git a/compiler/tests/integers/u16/mul.leo b/compiler/tests/integers/u16/mul.leo index 846d186653..4eba72e95e 100644 --- a/compiler/tests/integers/u16/mul.leo +++ b/compiler/tests/integers/u16/mul.leo @@ -1,3 +1,3 @@ function main(a: u16, b: u16) -> u16 { - return a * b + return a * b } \ No newline at end of file diff --git a/compiler/tests/integers/u16/pow.leo b/compiler/tests/integers/u16/pow.leo index 1d938456e5..d772278ddc 100644 --- a/compiler/tests/integers/u16/pow.leo +++ b/compiler/tests/integers/u16/pow.leo @@ -1,3 +1,3 @@ function main(a: u16, b: u16) -> u16 { - return a ** b + return a ** b } \ No newline at end of file diff --git a/compiler/tests/integers/u16/sub.leo b/compiler/tests/integers/u16/sub.leo index 07d27a8c12..6c3f358a67 100644 --- a/compiler/tests/integers/u16/sub.leo +++ b/compiler/tests/integers/u16/sub.leo @@ -1,3 +1,3 @@ function main(a: u16, b: u16) -> u16 { - return a - b + return a - b } \ No newline at end of file diff --git a/compiler/tests/integers/u16/ternary.leo b/compiler/tests/integers/u16/ternary.leo index cf0f66b05d..2c45a21b4f 100644 --- a/compiler/tests/integers/u16/ternary.leo +++ b/compiler/tests/integers/u16/ternary.leo @@ -1,3 +1,3 @@ function main(b: bool, x: u16, y: u16) -> u16 { - return if b ? x : y + return if b ? x : y } \ No newline at end of file diff --git a/compiler/tests/integers/u32/add.leo b/compiler/tests/integers/u32/add.leo index 853227e557..63b288881e 100644 --- a/compiler/tests/integers/u32/add.leo +++ b/compiler/tests/integers/u32/add.leo @@ -1,3 +1,3 @@ function main(a: u32, b: u32) -> u32 { - return a + b + return a + b } \ No newline at end of file diff --git a/compiler/tests/integers/u32/assert_eq.leo b/compiler/tests/integers/u32/assert_eq.leo index 768816d9c8..b95ae3bef0 100644 --- a/compiler/tests/integers/u32/assert_eq.leo +++ b/compiler/tests/integers/u32/assert_eq.leo @@ -1,3 +1,3 @@ function main(a: u32, b: u32) { - assert_eq!(a, b); + assert_eq!(a, b); } \ No newline at end of file diff --git a/compiler/tests/integers/u32/div.leo b/compiler/tests/integers/u32/div.leo index e75a9e425e..fe9f4b4c30 100644 --- a/compiler/tests/integers/u32/div.leo +++ b/compiler/tests/integers/u32/div.leo @@ -1,3 +1,3 @@ function main(a: u32, b: u32) -> u32 { - return a / b + return a / b } \ No newline at end of file diff --git a/compiler/tests/integers/u32/eq.leo b/compiler/tests/integers/u32/eq.leo index 65c5501219..5a4810ded2 100644 --- a/compiler/tests/integers/u32/eq.leo +++ b/compiler/tests/integers/u32/eq.leo @@ -1,3 +1,3 @@ function main(a: u32, b: u32) -> bool { - return a == b + return a == b } \ No newline at end of file diff --git a/compiler/tests/integers/u32/ge.leo b/compiler/tests/integers/u32/ge.leo index d08a3e8708..d0fdfe346d 100644 --- a/compiler/tests/integers/u32/ge.leo +++ b/compiler/tests/integers/u32/ge.leo @@ -1,3 +1,3 @@ function main(a: u32, b: u32) -> bool { - return a >= b + return a >= b } \ No newline at end of file diff --git a/compiler/tests/integers/u32/gt.leo b/compiler/tests/integers/u32/gt.leo index abd9832804..87aef82e4a 100644 --- a/compiler/tests/integers/u32/gt.leo +++ b/compiler/tests/integers/u32/gt.leo @@ -1,3 +1,3 @@ function main(a: u32, b: u32) -> bool { - return a > b + return a > b } \ No newline at end of file diff --git a/compiler/tests/integers/u32/input.leo b/compiler/tests/integers/u32/input.leo index 904b6ca60a..1d6d071c2c 100644 --- a/compiler/tests/integers/u32/input.leo +++ b/compiler/tests/integers/u32/input.leo @@ -1,3 +1,3 @@ function main(x: u32) -> u32 { - return x + return x } \ No newline at end of file diff --git a/compiler/tests/integers/u32/le.leo b/compiler/tests/integers/u32/le.leo index c16b861679..229ecdf340 100644 --- a/compiler/tests/integers/u32/le.leo +++ b/compiler/tests/integers/u32/le.leo @@ -1,3 +1,3 @@ function main(a: u32, b: u32) -> bool { - return a <= b + return a <= b } \ No newline at end of file diff --git a/compiler/tests/integers/u32/lt.leo b/compiler/tests/integers/u32/lt.leo index 3d06c38456..31093aaa28 100644 --- a/compiler/tests/integers/u32/lt.leo +++ b/compiler/tests/integers/u32/lt.leo @@ -1,3 +1,3 @@ function main(a: u32, b: u32) -> bool { - return a < b + return a < b } \ No newline at end of file diff --git a/compiler/tests/integers/u32/max.leo b/compiler/tests/integers/u32/max.leo index c15a4852e6..b08a1b5ef7 100644 --- a/compiler/tests/integers/u32/max.leo +++ b/compiler/tests/integers/u32/max.leo @@ -1,3 +1,3 @@ function main() -> u32 { - return 4294967295 + return 4294967295 } \ No newline at end of file diff --git a/compiler/tests/integers/u32/min.leo b/compiler/tests/integers/u32/min.leo index db6446d5c5..2bda23cdc5 100644 --- a/compiler/tests/integers/u32/min.leo +++ b/compiler/tests/integers/u32/min.leo @@ -1,3 +1,3 @@ function main() -> u32 { - return 0 + return 0 } \ No newline at end of file diff --git a/compiler/tests/integers/u32/mod.rs b/compiler/tests/integers/u32/mod.rs index ec9cbb3d06..ce5cf6f951 100644 --- a/compiler/tests/integers/u32/mod.rs +++ b/compiler/tests/integers/u32/mod.rs @@ -46,43 +46,79 @@ pub(crate) fn output_one(program: EdwardsTestCompiler) { output_number(program, 1u32); } +test_uint!(TestU32, u32, IntegerType::U32Type(U32Type {}), UInt32); + #[test] -fn test_u32() { - test_uint!(TestU32, u32, IntegerType::U32Type(U32Type {}), UInt32); - +fn test_u32_min() { TestU32::test_min(std::u32::MIN); +} + +#[test] +fn test_u32_max() { TestU32::test_max(std::u32::MAX); +} +#[test] +fn test_u32_input() { TestU32::test_input(); +} +#[test] +fn test_u32_add() { TestU32::test_add(); - // TestU32::test_sub(); //Todo: Catch subtraction overflow error in gadget +} + +#[test] +fn test_u32_sub() { + TestU32::test_sub(); +} + +#[test] +fn test_u32_mul() { TestU32::test_mul(); +} + +#[test] +fn test_u32_div() { TestU32::test_div(); - TestU32::test_pow(); // takes about 2 mins +} +#[test] +fn test_u32_pow() { + TestU32::test_pow(); +} + +#[test] +fn test_u32_eq() { TestU32::test_eq(); - TestU32::test_ge(); - TestU32::test_gt(); - TestU32::test_le(); - TestU32::test_gt(); +} +#[test] +fn test_u32_ge() { + TestU32::test_ge(); +} + +#[test] +fn test_u32_gt() { + TestU32::test_gt(); +} + +#[test] +fn test_u32_le() { + TestU32::test_le(); +} + +#[test] +fn test_u32_lt() { + TestU32::test_lt(); +} + +#[test] +fn test_u32_assert_eq() { TestU32::test_assert_eq(); +} + +#[test] +fn test_u32_ternary() { TestU32::test_ternary(); } - -#[test] -fn test_zero() { - let bytes = include_bytes!("zero.leo"); - let program = parse_program(bytes).unwrap(); - - output_zero(program); -} - -#[test] -fn test_one() { - let bytes = include_bytes!("one.leo"); - let program = parse_program(bytes).unwrap(); - - output_one(program); -} diff --git a/compiler/tests/integers/u32/mul.leo b/compiler/tests/integers/u32/mul.leo index 14e6ad10a9..c549375c63 100644 --- a/compiler/tests/integers/u32/mul.leo +++ b/compiler/tests/integers/u32/mul.leo @@ -1,3 +1,3 @@ function main(a: u32, b: u32) -> u32 { - return a * b + return a * b } \ No newline at end of file diff --git a/compiler/tests/integers/u32/pow.leo b/compiler/tests/integers/u32/pow.leo index 5bf0811693..6a9b24e424 100644 --- a/compiler/tests/integers/u32/pow.leo +++ b/compiler/tests/integers/u32/pow.leo @@ -1,3 +1,3 @@ function main(a: u32, b: u32) -> u32 { - return a ** b + return a ** b } \ No newline at end of file diff --git a/compiler/tests/integers/u32/sub.leo b/compiler/tests/integers/u32/sub.leo index d95eceea1e..aa430d5b46 100644 --- a/compiler/tests/integers/u32/sub.leo +++ b/compiler/tests/integers/u32/sub.leo @@ -1,3 +1,3 @@ function main(a: u32, b: u32) -> u32 { - return a - b + return a - b } \ No newline at end of file diff --git a/compiler/tests/integers/u32/ternary.leo b/compiler/tests/integers/u32/ternary.leo index ffbeec8a3b..cd957c2a38 100644 --- a/compiler/tests/integers/u32/ternary.leo +++ b/compiler/tests/integers/u32/ternary.leo @@ -1,3 +1,3 @@ function main(b: bool, x: u32, y: u32) -> u32 { - return if b ? x : y + return if b ? x : y } \ No newline at end of file diff --git a/compiler/tests/integers/u64/add.leo b/compiler/tests/integers/u64/add.leo index 6101f0c9fe..d7850737fe 100644 --- a/compiler/tests/integers/u64/add.leo +++ b/compiler/tests/integers/u64/add.leo @@ -1,3 +1,3 @@ function main(a: u64, b: u64) -> u64 { - return a + b + return a + b } \ No newline at end of file diff --git a/compiler/tests/integers/u64/assert_eq.leo b/compiler/tests/integers/u64/assert_eq.leo index 0858ffbc54..5ea21a4097 100644 --- a/compiler/tests/integers/u64/assert_eq.leo +++ b/compiler/tests/integers/u64/assert_eq.leo @@ -1,3 +1,3 @@ function main(a: u64, b: u64) { - assert_eq!(a, b); + assert_eq!(a, b); } \ No newline at end of file diff --git a/compiler/tests/integers/u64/div.leo b/compiler/tests/integers/u64/div.leo index a0b39d3f13..3ee457c9f6 100644 --- a/compiler/tests/integers/u64/div.leo +++ b/compiler/tests/integers/u64/div.leo @@ -1,3 +1,3 @@ function main(a: u64, b: u64) -> u64 { - return a / b + return a / b } \ No newline at end of file diff --git a/compiler/tests/integers/u64/eq.leo b/compiler/tests/integers/u64/eq.leo index 3e4d311918..658fc442fa 100644 --- a/compiler/tests/integers/u64/eq.leo +++ b/compiler/tests/integers/u64/eq.leo @@ -1,3 +1,3 @@ function main(a: u64, b: u64) -> bool { - return a == b + return a == b } \ No newline at end of file diff --git a/compiler/tests/integers/u64/ge.leo b/compiler/tests/integers/u64/ge.leo index 0997be8f64..696501c52f 100644 --- a/compiler/tests/integers/u64/ge.leo +++ b/compiler/tests/integers/u64/ge.leo @@ -1,3 +1,3 @@ function main(a: u64, b: u64) -> bool { - return a >= b + return a >= b } \ No newline at end of file diff --git a/compiler/tests/integers/u64/gt.leo b/compiler/tests/integers/u64/gt.leo index b894ff2e99..5aa797aba6 100644 --- a/compiler/tests/integers/u64/gt.leo +++ b/compiler/tests/integers/u64/gt.leo @@ -1,3 +1,3 @@ function main(a: u64, b: u64) -> bool { - return a > b + return a > b } \ No newline at end of file diff --git a/compiler/tests/integers/u64/input.leo b/compiler/tests/integers/u64/input.leo index b570511bf3..b12c15e14f 100644 --- a/compiler/tests/integers/u64/input.leo +++ b/compiler/tests/integers/u64/input.leo @@ -1,3 +1,3 @@ function main(x: u64) -> u64 { - return x + return x } \ No newline at end of file diff --git a/compiler/tests/integers/u64/le.leo b/compiler/tests/integers/u64/le.leo index 2c89a0c3c7..a9dfdf1ed1 100644 --- a/compiler/tests/integers/u64/le.leo +++ b/compiler/tests/integers/u64/le.leo @@ -1,3 +1,3 @@ function main(a: u64, b: u64) -> bool { - return a <= b + return a <= b } \ No newline at end of file diff --git a/compiler/tests/integers/u64/lt.leo b/compiler/tests/integers/u64/lt.leo index 58a86b078d..a50a8f8ee3 100644 --- a/compiler/tests/integers/u64/lt.leo +++ b/compiler/tests/integers/u64/lt.leo @@ -1,3 +1,3 @@ function main(a: u64, b: u64) -> bool { - return a < b + return a < b } \ No newline at end of file diff --git a/compiler/tests/integers/u64/max.leo b/compiler/tests/integers/u64/max.leo index 35ddbbb5fb..004816a9ce 100644 --- a/compiler/tests/integers/u64/max.leo +++ b/compiler/tests/integers/u64/max.leo @@ -1,3 +1,3 @@ function main() -> u64 { - return 18446744073709551615 + return 18446744073709551615 } \ No newline at end of file diff --git a/compiler/tests/integers/u64/min.leo b/compiler/tests/integers/u64/min.leo index caeef76946..20e2cf3518 100644 --- a/compiler/tests/integers/u64/min.leo +++ b/compiler/tests/integers/u64/min.leo @@ -1,3 +1,3 @@ function main() -> u64 { - return 0 + return 0 } \ No newline at end of file diff --git a/compiler/tests/integers/u64/mod.rs b/compiler/tests/integers/u64/mod.rs index 5b5a277df1..924079e1c5 100644 --- a/compiler/tests/integers/u64/mod.rs +++ b/compiler/tests/integers/u64/mod.rs @@ -29,28 +29,80 @@ fn output_expected_allocated(program: EdwardsTestCompiler, expected: UInt64) { } } +test_uint!(TestU64, u64, IntegerType::U64Type(U64Type {}), UInt64); + #[test] -#[ignore] //temporarily ignore memory expensive tests for travis -fn test_u64() { - test_uint!(Testu64, u64, IntegerType::U64Type(U64Type {}), UInt64); - - Testu64::test_min(std::u64::MIN); - Testu64::test_max(std::u64::MAX); - - Testu64::test_input(); - - Testu64::test_add(); - // Testu64::test_sub(); //Todo: Catch subtraction overflow error in gadget - Testu64::test_mul(); - Testu64::test_div(); - Testu64::test_pow(); // takes ~2mins - - Testu64::test_eq(); - Testu64::test_ge(); - Testu64::test_gt(); - Testu64::test_le(); - Testu64::test_gt(); - - Testu64::test_assert_eq(); - Testu64::test_ternary(); +fn test_u64_min() { + TestU64::test_min(std::u64::MIN); +} + +#[test] +fn test_u64_max() { + TestU64::test_max(std::u64::MAX); +} + +#[test] +fn test_u64_input() { + TestU64::test_input(); +} + +#[test] +fn test_u64_add() { + TestU64::test_add(); +} + +#[test] +fn test_u64_sub() { + TestU64::test_sub(); +} + +#[test] +fn test_u64_mul() { + TestU64::test_mul(); +} + +#[test] +fn test_u64_div() { + TestU64::test_div(); +} + +#[test] +#[ignore] // this test takes ~7 mins +fn test_u64_pow() { + TestU64::test_pow(); +} + +#[test] +fn test_u64_eq() { + TestU64::test_eq(); +} + +#[test] +fn test_u64_ge() { + TestU64::test_ge(); +} + +#[test] +fn test_u64_gt() { + TestU64::test_gt(); +} + +#[test] +fn test_u64_le() { + TestU64::test_le(); +} + +#[test] +fn test_u64_lt() { + TestU64::test_lt(); +} + +#[test] +fn test_u64_assert_eq() { + TestU64::test_assert_eq(); +} + +#[test] +fn test_u64_ternary() { + TestU64::test_ternary(); } diff --git a/compiler/tests/integers/u64/mul.leo b/compiler/tests/integers/u64/mul.leo index 06d64a6507..fb64709694 100644 --- a/compiler/tests/integers/u64/mul.leo +++ b/compiler/tests/integers/u64/mul.leo @@ -1,3 +1,3 @@ function main(a: u64, b: u64) -> u64 { - return a * b + return a * b } \ No newline at end of file diff --git a/compiler/tests/integers/u64/pow.leo b/compiler/tests/integers/u64/pow.leo index 4b86849892..a2267f64e1 100644 --- a/compiler/tests/integers/u64/pow.leo +++ b/compiler/tests/integers/u64/pow.leo @@ -1,3 +1,3 @@ function main(a: u64, b: u64) -> u64 { - return a ** b + return a ** b } \ No newline at end of file diff --git a/compiler/tests/integers/u64/sub.leo b/compiler/tests/integers/u64/sub.leo index 6efe830937..55479de911 100644 --- a/compiler/tests/integers/u64/sub.leo +++ b/compiler/tests/integers/u64/sub.leo @@ -1,3 +1,3 @@ function main(a: u64, b: u64) -> u64 { - return a - b + return a - b } \ No newline at end of file diff --git a/compiler/tests/integers/u64/ternary.leo b/compiler/tests/integers/u64/ternary.leo index 99923eb1fd..befa05ef7a 100644 --- a/compiler/tests/integers/u64/ternary.leo +++ b/compiler/tests/integers/u64/ternary.leo @@ -1,3 +1,3 @@ function main(b: bool, x: u64, y: u64) -> u64 { - return if b ? x : y + return if b ? x : y } \ No newline at end of file diff --git a/compiler/tests/integers/u8/add.leo b/compiler/tests/integers/u8/add.leo index 2ac7260c91..297820fb7e 100644 --- a/compiler/tests/integers/u8/add.leo +++ b/compiler/tests/integers/u8/add.leo @@ -1,3 +1,3 @@ function main(a: u8, b: u8) -> u8 { - return a + b + return a + b } \ No newline at end of file diff --git a/compiler/tests/integers/u8/assert_eq.leo b/compiler/tests/integers/u8/assert_eq.leo index c97b89b054..c4ffe7b4a0 100644 --- a/compiler/tests/integers/u8/assert_eq.leo +++ b/compiler/tests/integers/u8/assert_eq.leo @@ -1,3 +1,3 @@ function main(a: u8, b: u8) { - assert_eq!(a, b); + assert_eq!(a, b); } \ No newline at end of file diff --git a/compiler/tests/integers/u8/div.leo b/compiler/tests/integers/u8/div.leo index 1592968545..97a6546b8f 100644 --- a/compiler/tests/integers/u8/div.leo +++ b/compiler/tests/integers/u8/div.leo @@ -1,3 +1,3 @@ function main(a: u8, b: u8) -> u8 { - return a / b + return a / b } \ No newline at end of file diff --git a/compiler/tests/integers/u8/eq.leo b/compiler/tests/integers/u8/eq.leo index a9b0a57d5b..0a8bd1fd8d 100644 --- a/compiler/tests/integers/u8/eq.leo +++ b/compiler/tests/integers/u8/eq.leo @@ -1,3 +1,3 @@ function main(a: u8, b: u8) -> bool { - return a == b + return a == b } \ No newline at end of file diff --git a/compiler/tests/integers/u8/ge.leo b/compiler/tests/integers/u8/ge.leo index eb0abe5666..8e00f7575a 100644 --- a/compiler/tests/integers/u8/ge.leo +++ b/compiler/tests/integers/u8/ge.leo @@ -1,3 +1,3 @@ function main(a: u8, b: u8) -> bool { - return a >= b + return a >= b } \ No newline at end of file diff --git a/compiler/tests/integers/u8/gt.leo b/compiler/tests/integers/u8/gt.leo index 058bedfced..5af71ef04d 100644 --- a/compiler/tests/integers/u8/gt.leo +++ b/compiler/tests/integers/u8/gt.leo @@ -1,3 +1,3 @@ function main(a: u8, b: u8) -> bool { - return a > b + return a > b } \ No newline at end of file diff --git a/compiler/tests/integers/u8/input.leo b/compiler/tests/integers/u8/input.leo index d962c67be9..28d6f3e80e 100644 --- a/compiler/tests/integers/u8/input.leo +++ b/compiler/tests/integers/u8/input.leo @@ -1,3 +1,3 @@ function main(x: u8) -> u8 { - return x + return x } \ No newline at end of file diff --git a/compiler/tests/integers/u8/le.leo b/compiler/tests/integers/u8/le.leo index d3a4631982..bfe459dcd1 100644 --- a/compiler/tests/integers/u8/le.leo +++ b/compiler/tests/integers/u8/le.leo @@ -1,3 +1,3 @@ function main(a: u8, b: u8) -> bool { - return a <= b + return a <= b } \ No newline at end of file diff --git a/compiler/tests/integers/u8/lt.leo b/compiler/tests/integers/u8/lt.leo index 1f92818dd6..1434643dde 100644 --- a/compiler/tests/integers/u8/lt.leo +++ b/compiler/tests/integers/u8/lt.leo @@ -1,3 +1,3 @@ function main(a: u8, b: u8) -> bool { - return a < b + return a < b } \ No newline at end of file diff --git a/compiler/tests/integers/u8/max.leo b/compiler/tests/integers/u8/max.leo index 9ffefc95fa..06aebc3936 100644 --- a/compiler/tests/integers/u8/max.leo +++ b/compiler/tests/integers/u8/max.leo @@ -1,3 +1,3 @@ function main() -> u8 { - return 255 + return 255 } \ No newline at end of file diff --git a/compiler/tests/integers/u8/min.leo b/compiler/tests/integers/u8/min.leo index 6e680d5c52..fe2a219c54 100644 --- a/compiler/tests/integers/u8/min.leo +++ b/compiler/tests/integers/u8/min.leo @@ -1,3 +1,3 @@ function main() -> u8 { - return 0 + return 0 } \ No newline at end of file diff --git a/compiler/tests/integers/u8/mod.rs b/compiler/tests/integers/u8/mod.rs index ae0868860c..f872a6c3b9 100644 --- a/compiler/tests/integers/u8/mod.rs +++ b/compiler/tests/integers/u8/mod.rs @@ -29,27 +29,79 @@ fn output_expected_allocated(program: EdwardsTestCompiler, expected: UInt8) { } } +test_uint!(TestU8, u8, IntegerType::U8Type(U8Type {}), UInt8); + #[test] -fn test_u8() { - test_uint!(Testu8, u8, IntegerType::U8Type(U8Type {}), UInt8); - - Testu8::test_min(std::u8::MIN); - Testu8::test_max(std::u8::MAX); - - Testu8::test_input(); - - Testu8::test_add(); - // Testu8::test_sub(); //Todo: Catch subtraction overflow error in gadget - Testu8::test_mul(); - Testu8::test_div(); - Testu8::test_pow(); - - Testu8::test_eq(); - Testu8::test_ge(); - Testu8::test_gt(); - Testu8::test_le(); - Testu8::test_gt(); - - Testu8::test_assert_eq(); - Testu8::test_ternary(); +fn test_u8_min() { + TestU8::test_min(std::u8::MIN); +} + +#[test] +fn test_u8_max() { + TestU8::test_max(std::u8::MAX); +} + +#[test] +fn test_u8_input() { + TestU8::test_input(); +} + +#[test] +fn test_u8_add() { + TestU8::test_add(); +} + +#[test] +fn test_u8_sub() { + TestU8::test_sub(); +} + +#[test] +fn test_u8_mul() { + TestU8::test_mul(); +} + +#[test] +fn test_u8_div() { + TestU8::test_div(); +} + +#[test] +fn test_u8_pow() { + TestU8::test_pow(); +} + +#[test] +fn test_u8_eq() { + TestU8::test_eq(); +} + +#[test] +fn test_u8_ge() { + TestU8::test_ge(); +} + +#[test] +fn test_u8_gt() { + TestU8::test_gt(); +} + +#[test] +fn test_u8_le() { + TestU8::test_le(); +} + +#[test] +fn test_u8_lt() { + TestU8::test_lt(); +} + +#[test] +fn test_u8_assert_eq() { + TestU8::test_assert_eq(); +} + +#[test] +fn test_u8_ternary() { + TestU8::test_ternary(); } diff --git a/compiler/tests/integers/u8/mul.leo b/compiler/tests/integers/u8/mul.leo index 5cfc59387c..51d11c8b58 100644 --- a/compiler/tests/integers/u8/mul.leo +++ b/compiler/tests/integers/u8/mul.leo @@ -1,3 +1,3 @@ function main(a: u8, b: u8) -> u8 { - return a * b + return a * b } \ No newline at end of file diff --git a/compiler/tests/integers/u8/pow.leo b/compiler/tests/integers/u8/pow.leo index 9430e1b931..2e4c4fef95 100644 --- a/compiler/tests/integers/u8/pow.leo +++ b/compiler/tests/integers/u8/pow.leo @@ -1,3 +1,3 @@ function main(a: u8, b: u8) -> u8 { - return a ** b + return a ** b } \ No newline at end of file diff --git a/compiler/tests/integers/u8/sub.leo b/compiler/tests/integers/u8/sub.leo index e8b28396b4..e1420f05bb 100644 --- a/compiler/tests/integers/u8/sub.leo +++ b/compiler/tests/integers/u8/sub.leo @@ -1,3 +1,3 @@ function main(a: u8, b: u8) -> u8 { - return a - b + return a - b } \ No newline at end of file diff --git a/compiler/tests/integers/u8/ternary.leo b/compiler/tests/integers/u8/ternary.leo index 0a9db649c5..1a4ca0ba5f 100644 --- a/compiler/tests/integers/u8/ternary.leo +++ b/compiler/tests/integers/u8/ternary.leo @@ -1,3 +1,3 @@ function main(b: bool, x: u8, y: u8) -> u8 { - return if b ? x : y + return if b ? x : y } \ No newline at end of file diff --git a/compiler/tests/integers/macros.rs b/compiler/tests/integers/uint_macro.rs similarity index 75% rename from compiler/tests/integers/macros.rs rename to compiler/tests/integers/uint_macro.rs index 81eb459f98..60def3c225 100644 --- a/compiler/tests/integers/macros.rs +++ b/compiler/tests/integers/uint_macro.rs @@ -1,9 +1,9 @@ macro_rules! test_uint { - ($name: ident, $_type: ty, $integer_type: expr, $gadget: ty) => { + ($name: ident, $type_: ty, $integer_type: expr, $gadget: ty) => { pub struct $name {} impl $name { - fn test_min(min: $_type) { + fn test_min(min: $type_) { let min_allocated = <$gadget>::constant(min); let bytes = include_bytes!("min.leo"); @@ -12,7 +12,7 @@ macro_rules! test_uint { output_expected_allocated(program, min_allocated); } - fn test_max(max: $_type) { + fn test_max(max: $type_) { let max_allocated = <$gadget>::constant(max); let bytes = include_bytes!("max.leo"); @@ -25,13 +25,13 @@ macro_rules! test_uint { impl IntegerTester for $name { fn test_input() { // valid input - let num: $_type = rand::random(); + let num: $type_ = rand::random(); let expected = <$gadget>::constant(num); let bytes = include_bytes!("input.leo"); let mut program = parse_program(bytes).unwrap(); - program.set_inputs(vec![Some(InputValue::Integer($integer_type, num as u128))]); + program.set_inputs(vec![Some(InputValue::Integer($integer_type, num.to_string()))]); output_expected_allocated(program, expected); @@ -49,8 +49,8 @@ macro_rules! test_uint { fn test_add() { for _ in 0..10 { - let r1: $_type = rand::random(); - let r2: $_type = rand::random(); + let r1: $type_ = rand::random(); + let r2: $type_ = rand::random(); let sum = r1.wrapping_add(r2); @@ -61,8 +61,8 @@ macro_rules! test_uint { let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r2 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), ]); output_expected_allocated(program, sum_allocated); @@ -71,10 +71,13 @@ macro_rules! test_uint { fn test_sub() { for _ in 0..10 { - let r1: $_type = rand::random(); - let r2: $_type = rand::random(); + let r1: $type_ = rand::random(); + let r2: $type_ = rand::random(); - let difference = r1.wrapping_sub(r2); + let difference = match r1.checked_sub(r2) { + Some(valid) => valid, + None => continue, + }; let cs = TestConstraintSystem::::new(); let difference_allocated = <$gadget>::alloc(cs, || Ok(difference)).unwrap(); @@ -83,8 +86,8 @@ macro_rules! test_uint { let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r2 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), ]); output_expected_allocated(program, difference_allocated); @@ -93,8 +96,8 @@ macro_rules! test_uint { fn test_mul() { for _ in 0..10 { - let r1: $_type = rand::random(); - let r2: $_type = rand::random(); + let r1: $type_ = rand::random(); + let r2: $type_ = rand::random(); let product = r1.wrapping_mul(r2); @@ -105,8 +108,8 @@ macro_rules! test_uint { let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r2 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), ]); output_expected_allocated(program, product_allocated); @@ -114,35 +117,35 @@ macro_rules! test_uint { } fn test_div() { - for _ in 0..10 { - let r1: $_type = rand::random(); - let r2: $_type = rand::random(); + // for _ in 0..10 {// these loops take an excessive amount of time + let r1: $type_ = rand::random(); + let r2: $type_ = rand::random(); - let bytes = include_bytes!("div.leo"); - let mut program = parse_program(bytes).unwrap(); + let bytes = include_bytes!("div.leo"); + let mut program = parse_program(bytes).unwrap(); - program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r2 as u128)), - ]); + program.set_inputs(vec![ + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), + ]); - // expect an error when dividing by zero - if r2 == 0 { - let _err = get_error(program); - } else { - let cs = TestConstraintSystem::::new(); - let quotient = r1.wrapping_div(r2); - let quotient_allocated = <$gadget>::alloc(cs, || Ok(quotient)).unwrap(); + // expect an error when dividing by zero + if r2 == 0 { + let _err = get_error(program); + } else { + let cs = TestConstraintSystem::::new(); + let quotient = r1.wrapping_div(r2); + let quotient_allocated = <$gadget>::alloc(cs, || Ok(quotient)).unwrap(); - output_expected_allocated(program, quotient_allocated); - } + output_expected_allocated(program, quotient_allocated); } + // } } fn test_pow() { // for _ in 0..10 {// these loops take an excessive amount of time - let r1: $_type = rand::random(); - let r2: $_type = rand::random(); + let r1: $type_ = rand::random(); + let r2: $type_ = rand::random(); let r2 = r2 as u32; // we cast to u32 here because of rust pow() requirements let result = r1.wrapping_pow(r2); @@ -154,8 +157,8 @@ macro_rules! test_uint { let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r2 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), ]); output_expected_allocated(program, result_allocated); @@ -164,29 +167,29 @@ macro_rules! test_uint { fn test_eq() { for _ in 0..10 { - let r1: $_type = rand::random(); + let r1: $type_ = rand::random(); // test equal let bytes = include_bytes!("eq.leo"); let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r1 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r1.to_string())), ]); output_true(program); // test not equal - let r2: $_type = rand::random(); + let r2: $type_ = rand::random(); let result = r1.eq(&r2); let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r2 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), ]); output_expected_boolean(program, result); @@ -195,29 +198,29 @@ macro_rules! test_uint { fn test_ge() { for _ in 0..10 { - let r1: $_type = rand::random(); + let r1: $type_ = rand::random(); // test equal let bytes = include_bytes!("ge.leo"); let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r1 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r1.to_string())), ]); output_true(program); // test not equal - let r2: $_type = rand::random(); + let r2: $type_ = rand::random(); let result = r1.ge(&r2); let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r2 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), ]); output_expected_boolean(program, result); @@ -226,29 +229,29 @@ macro_rules! test_uint { fn test_gt() { for _ in 0..10 { - let r1: $_type = rand::random(); + let r1: $type_ = rand::random(); // test equal let bytes = include_bytes!("gt.leo"); let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r1 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r1.to_string())), ]); output_false(program); // test not equal - let r2: $_type = rand::random(); + let r2: $type_ = rand::random(); let result = r1.gt(&r2); let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r2 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), ]); output_expected_boolean(program, result); @@ -257,29 +260,29 @@ macro_rules! test_uint { fn test_le() { for _ in 0..10 { - let r1: $_type = rand::random(); + let r1: $type_ = rand::random(); // test equal let bytes = include_bytes!("le.leo"); let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r1 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r1.to_string())), ]); output_true(program); // test not equal - let r2: $_type = rand::random(); + let r2: $type_ = rand::random(); let result = r1.le(&r2); let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r2 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), ]); output_expected_boolean(program, result); @@ -288,29 +291,28 @@ macro_rules! test_uint { fn test_lt() { for _ in 0..10 { - let r1: $_type = rand::random(); + let r1: $type_ = rand::random(); // test equal let bytes = include_bytes!("lt.leo"); let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r1 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r1.to_string())), ]); - output_false(program); // test not equal - let r2: $_type = rand::random(); + let r2: $type_ = rand::random(); let result = r1.lt(&r2); let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r2 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), ]); output_expected_boolean(program, result); @@ -319,21 +321,21 @@ macro_rules! test_uint { fn test_assert_eq() { for _ in 0..10 { - let r1: $_type = rand::random(); + let r1: $type_ = rand::random(); // test equal let bytes = include_bytes!("assert_eq.leo"); let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r1 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r1.to_string())), ]); let _ = get_output(program); // test not equal - let r2: $_type = rand::random(); + let r2: $type_ = rand::random(); if r1 == r2 { continue; @@ -342,8 +344,8 @@ macro_rules! test_uint { let mut program = parse_program(bytes).unwrap(); program.set_inputs(vec![ - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r2 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), ]); let mut cs = TestConstraintSystem::::new(); @@ -353,8 +355,8 @@ macro_rules! test_uint { } fn test_ternary() { - let r1: $_type = rand::random(); - let r2: $_type = rand::random(); + let r1: $type_ = rand::random(); + let r2: $type_ = rand::random(); let g1 = <$gadget>::constant(r1); let g2 = <$gadget>::constant(r2); @@ -367,8 +369,8 @@ macro_rules! test_uint { // true -> field 1 program_1.set_inputs(vec![ Some(InputValue::Boolean(true)), - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r2 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), ]); output_expected_allocated(program_1, g1); @@ -376,8 +378,8 @@ macro_rules! test_uint { // false -> field 2 program_2.set_inputs(vec![ Some(InputValue::Boolean(false)), - Some(InputValue::Integer($integer_type, r1 as u128)), - Some(InputValue::Integer($integer_type, r2 as u128)), + Some(InputValue::Integer($integer_type, r1.to_string())), + Some(InputValue::Integer($integer_type, r2.to_string())), ]); output_expected_allocated(program_2, g2); diff --git a/compiler/tests/mutability/array.leo b/compiler/tests/mutability/array.leo index 7475b636ab..1d51c15271 100644 --- a/compiler/tests/mutability/array.leo +++ b/compiler/tests/mutability/array.leo @@ -1,5 +1,5 @@ // Arrays are immutable by default. function main() { - let a = [1u32]; - a[0] = 0; + let a = [1u32]; + a[0] = 0; } \ No newline at end of file diff --git a/compiler/tests/mutability/array_mut.leo b/compiler/tests/mutability/array_mut.leo index 3f01b1e1ac..768f8fb092 100644 --- a/compiler/tests/mutability/array_mut.leo +++ b/compiler/tests/mutability/array_mut.leo @@ -1,7 +1,7 @@ // Adding the `mut` keyword makes an array variable mutable. function main() -> u32 { - let mut a = [1u32]; - a[0] = 0; + let mut a = [1u32]; + a[0] = 0; - return a[0] + return a[0] } \ No newline at end of file diff --git a/compiler/tests/mutability/circuit.leo b/compiler/tests/mutability/circuit.leo index c8334eddd0..be1c568836 100644 --- a/compiler/tests/mutability/circuit.leo +++ b/compiler/tests/mutability/circuit.leo @@ -1,9 +1,9 @@ // Circuits are immutable by default. -circuit Circ { - x: u32 +circuit Foo { + x: u32 } function main() { - let a = Circ { x: 1 }; - a.x = 0; + let a = Foo { x: 1 }; + a.x = 0; } \ No newline at end of file diff --git a/compiler/tests/mutability/circuit_mut.leo b/compiler/tests/mutability/circuit_mut.leo index bccf0ed82c..5d4ba9f14f 100644 --- a/compiler/tests/mutability/circuit_mut.leo +++ b/compiler/tests/mutability/circuit_mut.leo @@ -1,11 +1,11 @@ // Adding the `mut` keyword makes a circuit variable mutable. -circuit Circ { - x: u32 +circuit Foo { + x: u32 } function main() -> u32 { - let mut a = Circ { x: 1 }; - a.x = 0; + let mut a = Foo { x: 1 }; + a.x = 0; - return a.x + return a.x } \ No newline at end of file diff --git a/compiler/tests/mutability/const.leo b/compiler/tests/mutability/const.leo index a167625c02..44f9279085 100644 --- a/compiler/tests/mutability/const.leo +++ b/compiler/tests/mutability/const.leo @@ -1,5 +1,5 @@ // Constant variables are immutable by default. function main() { - const a = 1u32; - a = 0; + const a = 1u32; + a = 0; } \ No newline at end of file diff --git a/compiler/tests/mutability/const_mut.leo b/compiler/tests/mutability/const_mut.leo index 06dc51c222..ef194ae178 100644 --- a/compiler/tests/mutability/const_mut.leo +++ b/compiler/tests/mutability/const_mut.leo @@ -1,4 +1,4 @@ // Adding the `mut` keyword to a constant variable is illegal function main() { - const mut a = 1u32; + const mut a = 1u32; } \ No newline at end of file diff --git a/compiler/tests/mutability/function_input.leo b/compiler/tests/mutability/function_input.leo index 2096092c68..c3cef38959 100644 --- a/compiler/tests/mutability/function_input.leo +++ b/compiler/tests/mutability/function_input.leo @@ -1,4 +1,4 @@ // Function inputs are immutable by default. function main(a: u32) { - a = 0; + a = 0; } \ No newline at end of file diff --git a/compiler/tests/mutability/function_input_mut.leo b/compiler/tests/mutability/function_input_mut.leo index 760f2c4e25..accd891cfd 100644 --- a/compiler/tests/mutability/function_input_mut.leo +++ b/compiler/tests/mutability/function_input_mut.leo @@ -1,6 +1,6 @@ // Adding the `mut` keyword makes a function variable mutable. function main(mut a: u32) -> u32 { - a = 0; + a = 0; - return a + return a } \ No newline at end of file diff --git a/compiler/tests/mutability/let.leo b/compiler/tests/mutability/let.leo index fd2b5e1dbc..477e6b35f5 100644 --- a/compiler/tests/mutability/let.leo +++ b/compiler/tests/mutability/let.leo @@ -1,5 +1,5 @@ // Variables are immutable by default. function main() { - let a = 1u32; - a = 0; + let a = 1u32; + a = 0; } \ No newline at end of file diff --git a/compiler/tests/mutability/let_mut.leo b/compiler/tests/mutability/let_mut.leo index cf30e5223e..59af4c461a 100644 --- a/compiler/tests/mutability/let_mut.leo +++ b/compiler/tests/mutability/let_mut.leo @@ -1,7 +1,7 @@ // Adding the `mut` keyword makes a variable mutable. function main() -> u32 { - let mut a = 1u32; - a = 0; + let mut a = 1u32; + a = 0; - return a + return a } \ No newline at end of file diff --git a/compiler/tests/statements/assertion_basic.leo b/compiler/tests/statements/assertion_basic.leo index bcdf923c0b..6c1fe116d0 100644 --- a/compiler/tests/statements/assertion_basic.leo +++ b/compiler/tests/statements/assertion_basic.leo @@ -1,3 +1,3 @@ function main(b: bool) { - assert_eq!(b, true); + assert_eq!(b, true); } \ No newline at end of file diff --git a/compiler/tests/statements/conditional/assert.leo b/compiler/tests/statements/conditional/assert.leo index db9f1f2fed..c0c24db693 100644 --- a/compiler/tests/statements/conditional/assert.leo +++ b/compiler/tests/statements/conditional/assert.leo @@ -1,7 +1,7 @@ function main(bit: u32) { if bit == 1 { - assert_eq!(bit, 1); + assert_eq!(bit, 1); } else { - assert_eq!(bit, 0); + assert_eq!(bit, 0); } } diff --git a/compiler/tests/statements/conditional/chain.leo b/compiler/tests/statements/conditional/chain.leo index 159c94be8b..65b391c1e8 100644 --- a/compiler/tests/statements/conditional/chain.leo +++ b/compiler/tests/statements/conditional/chain.leo @@ -1,13 +1,13 @@ function main(bit: u32) -> u32 { - let mut result = 0u32; + let mut result = 0u32; - if bit == 1 { - result = 1; - } else if bit == 2 { - result = 2; - } else { - result = 3; - } + if bit == 1 { + result = 1; + } else if bit == 2 { + result = 2; + } else { + result = 3; + } - return result + return result } \ No newline at end of file diff --git a/compiler/tests/statements/conditional/for_loop.leo b/compiler/tests/statements/conditional/for_loop.leo index 2728e2d302..b8228333a2 100644 --- a/compiler/tests/statements/conditional/for_loop.leo +++ b/compiler/tests/statements/conditional/for_loop.leo @@ -1,11 +1,11 @@ function main(cond: bool) -> u32 { - let mut a = 0u32; + let mut a = 0u32; - if cond { - for i in 0..4 { - a += i; + if cond { + for i in 0..4 { + a += i; + } } - } - return a + return a } diff --git a/compiler/tests/statements/conditional/mod.rs b/compiler/tests/statements/conditional/mod.rs index 34e3cf0402..b9e8f959ae 100644 --- a/compiler/tests/statements/conditional/mod.rs +++ b/compiler/tests/statements/conditional/mod.rs @@ -35,17 +35,26 @@ fn test_assert() { // Check that an input value of 1 satisfies the constraint system - program_1_pass.set_inputs(vec![Some(InputValue::Integer(IntegerType::U32Type(U32Type {}), 1))]); + program_1_pass.set_inputs(vec![Some(InputValue::Integer( + IntegerType::U32Type(U32Type {}), + 1.to_string(), + ))]); empty_output_satisfied(program_1_pass); // Check that an input value of 0 satisfies the constraint system - program_0_pass.set_inputs(vec![Some(InputValue::Integer(IntegerType::U32Type(U32Type {}), 0))]); + program_0_pass.set_inputs(vec![Some(InputValue::Integer( + IntegerType::U32Type(U32Type {}), + 0.to_string(), + ))]); empty_output_satisfied(program_0_pass); // Check that an input value of 2 does not satisfy the constraint system - program_2_fail.set_inputs(vec![Some(InputValue::Integer(IntegerType::U32Type(U32Type {}), 2))]); + program_2_fail.set_inputs(vec![Some(InputValue::Integer( + IntegerType::U32Type(U32Type {}), + 2.to_string(), + ))]); let mut cs = TestConstraintSystem::::new(); let _output = program_2_fail.compile_constraints(&mut cs).unwrap(); assert!(!cs.is_satisfied()); @@ -59,12 +68,18 @@ fn test_mutate() { // Check that an input value of 1 satisfies the constraint system - program_1_true.set_inputs(vec![Some(InputValue::Integer(IntegerType::U32Type(U32Type {}), 1))]); + program_1_true.set_inputs(vec![Some(InputValue::Integer( + IntegerType::U32Type(U32Type {}), + 1.to_string(), + ))]); output_one(program_1_true); // Check that an input value of 0 satisfies the constraint system - program_0_pass.set_inputs(vec![Some(InputValue::Integer(IntegerType::U32Type(U32Type {}), 0))]); + program_0_pass.set_inputs(vec![Some(InputValue::Integer( + IntegerType::U32Type(U32Type {}), + 0.to_string(), + ))]); output_zero(program_0_pass); } @@ -93,15 +108,24 @@ fn test_chain() { let mut program_2_3 = program_1_1.clone(); // Check that an input of 1 outputs true - program_1_1.set_inputs(vec![Some(InputValue::Integer(IntegerType::U32Type(U32Type {}), 1))]); + program_1_1.set_inputs(vec![Some(InputValue::Integer( + IntegerType::U32Type(U32Type {}), + 1.to_string(), + ))]); output_number(program_1_1, 1u32); // Check that an input of 0 outputs true - program_2_2.set_inputs(vec![Some(InputValue::Integer(IntegerType::U32Type(U32Type {}), 2))]); + program_2_2.set_inputs(vec![Some(InputValue::Integer( + IntegerType::U32Type(U32Type {}), + 2.to_string(), + ))]); output_number(program_2_2, 2u32); // Check that an input of 0 outputs true - program_2_3.set_inputs(vec![Some(InputValue::Integer(IntegerType::U32Type(U32Type {}), 5))]); + program_2_3.set_inputs(vec![Some(InputValue::Integer( + IntegerType::U32Type(U32Type {}), + 5.to_string(), + ))]); output_number(program_2_3, 3u32); } diff --git a/compiler/tests/statements/conditional/mutate.leo b/compiler/tests/statements/conditional/mutate.leo index b0309f958b..67ec956874 100644 --- a/compiler/tests/statements/conditional/mutate.leo +++ b/compiler/tests/statements/conditional/mutate.leo @@ -1,11 +1,11 @@ function main(bit: u32) -> u32 { - let mut a = 5u32; + let mut a = 5u32; - if bit == 1 { - a = 1; - } else { - a = 0; - } + if bit == 1 { + a = 1; + } else { + a = 0; + } - return a + return a } diff --git a/compiler/tests/statements/conditional/nested.leo b/compiler/tests/statements/conditional/nested.leo index 7eb814c9f1..b4570077fc 100644 --- a/compiler/tests/statements/conditional/nested.leo +++ b/compiler/tests/statements/conditional/nested.leo @@ -1,12 +1,12 @@ function main(a: bool, b: bool) -> u32 { - let mut result = 0u32; + let mut result = 0u32; - if a { - result += 1; - if b { - result += 2; + if a { + result += 1; + if b { + result += 2; + } } - } - return result + return result } \ No newline at end of file diff --git a/compiler/tests/statements/iteration_basic.leo b/compiler/tests/statements/iteration_basic.leo index 0289a22795..19460cc543 100644 --- a/compiler/tests/statements/iteration_basic.leo +++ b/compiler/tests/statements/iteration_basic.leo @@ -1,8 +1,8 @@ function main() -> u32 { - let mut x = 4u32; - for i in 0..3 { - x -= 1; - } + let mut x = 4u32; + for i in 0..3 { + x -= 1; + } - return x + return x } \ No newline at end of file diff --git a/compiler/tests/statements/num_returns_fail.leo b/compiler/tests/statements/num_returns_fail.leo index 64cfa7b3e2..14b2fe6ad0 100644 --- a/compiler/tests/statements/num_returns_fail.leo +++ b/compiler/tests/statements/num_returns_fail.leo @@ -1,3 +1,3 @@ function main() -> (bool, bool) { - return true + return true } \ No newline at end of file diff --git a/compiler/tests/statements/ternary_basic.leo b/compiler/tests/statements/ternary_basic.leo index 2fd76fa0e8..26909325e0 100644 --- a/compiler/tests/statements/ternary_basic.leo +++ b/compiler/tests/statements/ternary_basic.leo @@ -1,3 +1,3 @@ function main(b: bool) -> u32 { - return if b ? 1 : 0 + return if b ? 1 : 0 } \ No newline at end of file diff --git a/compiler/tests/syntax/mod.rs b/compiler/tests/syntax/mod.rs index 7bd068c503..b851bfafb1 100644 --- a/compiler/tests/syntax/mod.rs +++ b/compiler/tests/syntax/mod.rs @@ -28,10 +28,10 @@ fn test_undefined() { assert_eq!( format!("{}", error), vec![ - " --> \"/test/src/main.leo\": 2:10", + " --> \"/test/src/main.leo\": 2:12", " |", - " 2 | return a", - " | ^", + " 2 | return a", + " | ^", " |", " = cannot find value `a` in this scope", ] diff --git a/compiler/tests/syntax/semicolon.leo b/compiler/tests/syntax/semicolon.leo index 63de5d217d..68cfa7cbe0 100644 --- a/compiler/tests/syntax/semicolon.leo +++ b/compiler/tests/syntax/semicolon.leo @@ -1,3 +1,3 @@ function main() { - let a = 0 + let a = 0 } \ No newline at end of file diff --git a/compiler/tests/syntax/undefined.leo b/compiler/tests/syntax/undefined.leo index 504ecc580c..856b07589a 100644 --- a/compiler/tests/syntax/undefined.leo +++ b/compiler/tests/syntax/undefined.leo @@ -1,3 +1,3 @@ function main() -> bool { - return a + return a } \ No newline at end of file diff --git a/gadgets/Cargo.toml b/gadgets/Cargo.toml new file mode 100644 index 0000000000..ceb3eb2a2e --- /dev/null +++ b/gadgets/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "leo-gadgets" +version = "0.1.0" +authors = ["The Aleo Team "] +edition = "2018" + +[dependencies] +snarkos-errors = { 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 } + +rand = { version = "0.7", default-features = false } +rand_xorshift = { version = "0.2", default-features = false } +thiserror = { version = "1.0" } + +[dev-dependencies] +snarkos-utilities = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", rev = "c7a56d9" } \ No newline at end of file diff --git a/gadgets/src/arithmetic/add.rs b/gadgets/src/arithmetic/add.rs new file mode 100644 index 0000000000..522da0819b --- /dev/null +++ b/gadgets/src/arithmetic/add.rs @@ -0,0 +1,38 @@ +use snarkos_errors::gadgets::SynthesisError; +use snarkos_models::{ + curves::{Field, PrimeField}, + gadgets::{ + r1cs::ConstraintSystem, + utilities::uint::{UInt, UInt128, UInt16, UInt32, UInt64, UInt8}, + }, +}; + +/// Returns addition of `self` + `other` in the constraint system. +pub trait Add +where + Self: std::marker::Sized, +{ + type ErrorType; + + #[must_use] + fn add>(&self, cs: CS, other: &Self) -> Result; +} + +// Implement unsigned integers +macro_rules! add_uint_impl { + ($($gadget: ident),*) => ($( + impl Add for $gadget { + type ErrorType = SynthesisError; + + fn add>( + &self, + cs: CS, + other: &Self + ) -> Result { + <$gadget as UInt>::addmany(cs, &[self.clone(), other.clone()]) + } + } + )*) +} + +add_uint_impl!(UInt8, UInt16, UInt32, UInt64, UInt128); diff --git a/gadgets/src/arithmetic/div.rs b/gadgets/src/arithmetic/div.rs new file mode 100644 index 0000000000..097ae5962e --- /dev/null +++ b/gadgets/src/arithmetic/div.rs @@ -0,0 +1,12 @@ +use snarkos_models::{curves::Field, gadgets::r1cs::ConstraintSystem}; + +/// Returns division of `self` / `other` in the constraint system. +pub trait Div +where + Self: std::marker::Sized, +{ + type ErrorType; + + #[must_use] + fn div>(&self, cs: CS, other: &Self) -> Result; +} diff --git a/gadgets/src/arithmetic/mod.rs b/gadgets/src/arithmetic/mod.rs new file mode 100644 index 0000000000..20cae8f65a --- /dev/null +++ b/gadgets/src/arithmetic/mod.rs @@ -0,0 +1,17 @@ +pub mod add; +pub use self::add::*; + +pub mod div; +pub use self::div::*; + +pub mod mul; +pub use self::mul::*; + +pub mod neg; +pub use self::neg::*; + +pub mod pow; +pub use self::pow::*; + +pub mod sub; +pub use self::sub::*; diff --git a/gadgets/src/arithmetic/mul.rs b/gadgets/src/arithmetic/mul.rs new file mode 100644 index 0000000000..207fa8b212 --- /dev/null +++ b/gadgets/src/arithmetic/mul.rs @@ -0,0 +1,12 @@ +use snarkos_models::{curves::Field, gadgets::r1cs::ConstraintSystem}; + +/// Returns multiplication of `self` * `other` in the constraint system. +pub trait Mul +where + Self: std::marker::Sized, +{ + type ErrorType; + + #[must_use] + fn mul>(&self, cs: CS, other: &Self) -> Result; +} diff --git a/gadgets/src/arithmetic/neg.rs b/gadgets/src/arithmetic/neg.rs new file mode 100644 index 0000000000..9eabb4d83f --- /dev/null +++ b/gadgets/src/arithmetic/neg.rs @@ -0,0 +1,36 @@ +use crate::bits::RippleCarryAdder; + +use snarkos_errors::gadgets::SynthesisError; +use snarkos_models::{ + curves::Field, + gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean}, +}; + +/// Returns a negated representation of `self` in the constraint system. +pub trait Neg +where + Self: std::marker::Sized, +{ + type ErrorType; + + #[must_use] + fn neg>(&self, cs: CS) -> Result; +} + +impl Neg for Vec { + type ErrorType = SynthesisError; + + fn neg>(&self, mut cs: CS) -> Result { + // flip all bits + let flipped: Self = self.iter().map(|bit| bit.not()).collect(); + + // add one + let mut one = vec![Boolean::constant(true)]; + one.append(&mut vec![Boolean::Constant(false); self.len() - 1]); + + let mut bits = flipped.add_bits(cs.ns(|| format!("add one")), &one)?; + let _carry = bits.pop(); // we already accounted for overflow above + + Ok(bits) + } +} diff --git a/gadgets/src/arithmetic/pow.rs b/gadgets/src/arithmetic/pow.rs new file mode 100644 index 0000000000..9cb07f95b1 --- /dev/null +++ b/gadgets/src/arithmetic/pow.rs @@ -0,0 +1,12 @@ +use snarkos_models::{curves::Field, gadgets::r1cs::ConstraintSystem}; + +/// Returns exponentiation of `self` ** `other` in the constraint system. +pub trait Pow +where + Self: std::marker::Sized, +{ + type ErrorType; + + #[must_use] + fn pow>(&self, cs: CS, other: &Self) -> Result; +} diff --git a/gadgets/src/arithmetic/sub.rs b/gadgets/src/arithmetic/sub.rs new file mode 100644 index 0000000000..370b375908 --- /dev/null +++ b/gadgets/src/arithmetic/sub.rs @@ -0,0 +1,12 @@ +use snarkos_models::{curves::Field, gadgets::r1cs::ConstraintSystem}; + +/// Returns subtraction of `self` - `other` in the constraint system. +pub trait Sub +where + Self: std::marker::Sized, +{ + type ErrorType; + + #[must_use] + fn sub>(&self, cs: CS, other: &Self) -> Result; +} diff --git a/gadgets/src/bits/adder.rs b/gadgets/src/bits/adder.rs new file mode 100644 index 0000000000..5461c9cb7e --- /dev/null +++ b/gadgets/src/bits/adder.rs @@ -0,0 +1,40 @@ +use snarkos_errors::gadgets::SynthesisError; +use snarkos_models::{ + curves::Field, + gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean}, +}; + +/// Single bit binary adder with carry bit +/// https://en.wikipedia.org/wiki/Adder_(electronics)#Full_adder +/// sum = (a XOR b) XOR carry +/// carry = a AND b OR carry AND (a XOR b) +/// Returns (sum, carry) +pub trait FullAdder<'a, F: Field> +where + Self: std::marker::Sized, +{ + fn add>( + cs: CS, + a: &'a Self, + b: &'a Self, + carry: &'a Self, + ) -> Result<(Self, Self), SynthesisError>; +} + +impl<'a, F: Field> FullAdder<'a, F> for Boolean { + fn add>( + mut cs: CS, + a: &'a Self, + b: &'a Self, + carry: &'a Self, + ) -> Result<(Self, Self), SynthesisError> { + let a_x_b = Boolean::xor(cs.ns(|| format!("a XOR b")), a, b)?; + let sum = Boolean::xor(cs.ns(|| format!("adder sum")), &a_x_b, carry)?; + + let c1 = Boolean::and(cs.ns(|| format!("a AND b")), a, b)?; + let c2 = Boolean::and(cs.ns(|| format!("carry AND (a XOR b)")), carry, &a_x_b)?; + let carry = Boolean::or(cs.ns(|| format!("c1 OR c2")), &c1, &c2)?; + + Ok((sum, carry)) + } +} diff --git a/gadgets/src/bits/comparator.rs b/gadgets/src/bits/comparator.rs new file mode 100644 index 0000000000..1af89900a0 --- /dev/null +++ b/gadgets/src/bits/comparator.rs @@ -0,0 +1,82 @@ +use snarkos_errors::gadgets::SynthesisError; +use snarkos_models::{ + curves::{Field, PrimeField}, + gadgets::{ + r1cs::ConstraintSystem, + utilities::{ + boolean::Boolean, + select::CondSelectGadget, + uint::{UInt128, UInt16, UInt32, UInt64, UInt8}, + }, + }, +}; + +pub trait EvaluateLtGadget { + fn less_than>(&self, cs: CS, other: &Self) -> Result; +} + +// implementing `EvaluateLtGadget` will implement `ComparatorGadget` +pub trait ComparatorGadget +where + Self: EvaluateLtGadget, +{ + fn greater_than>(&self, cs: CS, other: &Self) -> Result { + other.less_than(cs, self) + } + + fn less_than_or_equal>(&self, cs: CS, other: &Self) -> Result { + let is_gt = self.greater_than(cs, other)?; + Ok(is_gt.not()) + } + + fn greater_than_or_equal>(&self, cs: CS, other: &Self) -> Result { + other.less_than_or_equal(cs, self) + } +} + +macro_rules! uint_cmp_impl { + ($($gadget: ident),*) => ($( + /* Bitwise less than comparison of two unsigned integers */ + impl EvaluateLtGadget for $gadget { + fn less_than>(&self, mut cs: CS, other: &Self) -> Result { + + let mut result = Boolean::constant(true); + let mut all_equal = Boolean::constant(true); + + // msb -> lsb + for (i, (a, b)) in self + .bits + .iter() + .rev() + .zip(other.bits.iter().rev()) + .enumerate() + { + // a == 0 & b == 1 + let less = Boolean::and(cs.ns(|| format!("not a and b [{}]", i)), &a.not(), b)?; + + // a == b = !(a ^ b) + let not_equal = Boolean::xor(cs.ns(|| format!("a XOR b [{}]", i)), a, b)?; + let equal = not_equal.not(); + + // evaluate a <= b + let less_or_equal = Boolean::or(cs.ns(|| format!("less or equal [{}]", i)), &less, &equal)?; + + // select the current result if it is the first bit difference + result = Boolean::conditionally_select(cs.ns(|| format!("select bit [{}]", i)), &all_equal, &less_or_equal, &result)?; + + // keep track of equal bits + all_equal = Boolean::and(cs.ns(|| format!("accumulate equal [{}]", i)), &all_equal, &equal)?; + } + + result = Boolean::and(cs.ns(|| format!("false if all equal")), &result, &all_equal.not())?; + + Ok(result) + } + } + + /* Bitwise comparison of two unsigned integers */ + impl ComparatorGadget for $gadget {} + )*) +} + +uint_cmp_impl!(UInt8, UInt16, UInt32, UInt64, UInt128); diff --git a/gadgets/src/bits/mod.rs b/gadgets/src/bits/mod.rs new file mode 100644 index 0000000000..6e55c89964 --- /dev/null +++ b/gadgets/src/bits/mod.rs @@ -0,0 +1,12 @@ +#[macro_use] +pub mod adder; +pub use self::adder::*; + +pub mod comparator; +pub use self::comparator::*; + +pub mod rca; +pub use self::rca::*; + +pub mod sign_extend; +pub use self::sign_extend::*; diff --git a/gadgets/src/bits/rca.rs b/gadgets/src/bits/rca.rs new file mode 100644 index 0000000000..72c24d03a2 --- /dev/null +++ b/gadgets/src/bits/rca.rs @@ -0,0 +1,47 @@ +use crate::{bits::FullAdder, signed_integer::*}; + +use snarkos_errors::gadgets::SynthesisError; +use snarkos_models::{ + curves::{Field, PrimeField}, + gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean}, +}; + +/// Returns the bitwise sum of a n-bit number with carry bit +pub trait RippleCarryAdder +where + Self: std::marker::Sized, +{ + #[must_use] + fn add_bits>(&self, cs: CS, other: &Self) -> Result, SynthesisError>; +} + +// Generic impl +impl RippleCarryAdder for Vec { + fn add_bits>(&self, mut cs: CS, other: &Self) -> Result, SynthesisError> { + let mut result = vec![]; + let mut carry = Boolean::constant(false); + for (i, (a, b)) in self.iter().zip(other.iter()).enumerate() { + let (sum, next) = Boolean::add(cs.ns(|| format!("rpc {}", i)), a, b, &carry)?; + + carry = next; + result.push(sum); + } + + // append the carry bit to the end + result.push(carry); + + Ok(result) + } +} + +macro_rules! rpc_impl { + ($($gadget: ident)*) => ($( + impl RippleCarryAdder for $gadget { + fn add_bits>(&self, cs: CS, other: &Self) -> Result, SynthesisError> { + self.bits.add_bits(cs, &other.bits) + } + } + )*) +} + +rpc_impl!(Int8 Int16 Int32 Int64 Int128); diff --git a/gadgets/src/bits/sign_extend.rs b/gadgets/src/bits/sign_extend.rs new file mode 100644 index 0000000000..63a8777904 --- /dev/null +++ b/gadgets/src/bits/sign_extend.rs @@ -0,0 +1,24 @@ +use snarkos_models::gadgets::utilities::boolean::Boolean; + +/// Sign extends an array of bits to the desired length. +/// Expects least significant bit first +pub trait SignExtend +where + Self: std::marker::Sized, +{ + #[must_use] + fn sign_extend(bits: &[Boolean], length: usize) -> Vec; +} + +impl SignExtend for Boolean { + fn sign_extend(bits: &[Boolean], length: usize) -> Vec { + let msb = bits.last().expect("empty bit list"); + let bits_needed = length - bits.len(); + let mut extension = vec![msb.clone(); bits_needed]; + + let mut result = Vec::from(bits); + result.append(&mut extension); + + result + } +} diff --git a/gadgets/src/errors/mod.rs b/gadgets/src/errors/mod.rs new file mode 100644 index 0000000000..3a4d43aad7 --- /dev/null +++ b/gadgets/src/errors/mod.rs @@ -0,0 +1,2 @@ +pub mod signed_integer; +pub use self::signed_integer::*; diff --git a/gadgets/src/errors/signed_integer.rs b/gadgets/src/errors/signed_integer.rs new file mode 100644 index 0000000000..759661435c --- /dev/null +++ b/gadgets/src/errors/signed_integer.rs @@ -0,0 +1,13 @@ +use snarkos_errors::gadgets::SynthesisError; + +#[derive(Debug, Error)] +pub enum SignedIntegerError { + #[error("Integer overflow")] + Overflow, + + #[error("Division by zero")] + DivisionByZero, + + #[error("{}", _0)] + SynthesisError(#[from] SynthesisError), +} diff --git a/gadgets/src/lib.rs b/gadgets/src/lib.rs new file mode 100644 index 0000000000..6d7eacfe77 --- /dev/null +++ b/gadgets/src/lib.rs @@ -0,0 +1,11 @@ +#[macro_use] +extern crate thiserror; + +pub mod arithmetic; + +pub mod bits; + +pub mod errors; + +pub mod signed_integer; +pub use self::signed_integer::*; diff --git a/gadgets/src/signed_integer/arithmetic/add.rs b/gadgets/src/signed_integer/arithmetic/add.rs new file mode 100644 index 0000000000..e2f2ae966b --- /dev/null +++ b/gadgets/src/signed_integer/arithmetic/add.rs @@ -0,0 +1,141 @@ +use crate::{ + arithmetic::Add, + bits::RippleCarryAdder, + errors::SignedIntegerError, + Int, + Int128, + Int16, + Int32, + Int64, + Int8, +}; + +use snarkos_models::{ + curves::{fp_parameters::FpParameters, PrimeField}, + gadgets::{ + r1cs::{Assignment, ConstraintSystem, LinearCombination}, + utilities::{ + alloc::AllocGadget, + boolean::{AllocatedBit, Boolean}, + }, + }, +}; + +macro_rules! add_int_impl { + ($($gadget: ident)*) => ($( + impl Add for $gadget { + type ErrorType = SignedIntegerError; + + fn add>(&self, mut cs: CS, other: &Self) -> Result { + // Compute the maximum value of the sum + let max_bits = <$gadget as Int>::SIZE; + + // Make some arbitrary bounds for ourselves to avoid overflows + // in the scalar field + assert!(F::Params::MODULUS_BITS >= max_bits as u32); + + // Accumulate the value + let result_value = match (self.value, other.value) { + (Some(a), Some(b)) => { + // check for addition overflow here + let val = match a.checked_add(b) { + Some(val) => val, + None => return Err(SignedIntegerError::Overflow) + }; + + Some(val) + }, + _ => { + // If any of the operands have unknown value, we won't + // know the value of the result + None + } + }; + + // This is a linear combination that we will enforce to be zero + let mut lc = LinearCombination::zero(); + + let mut all_constants = true; + + let mut bits = self.add_bits(cs.ns(|| format!("bits")), other)?; + + // we discard the carry since we check for overflow above + let _carry = bits.pop(); + + // Iterate over each bit_gadget of result and add each bit to + // the linear combination + let mut coeff = F::one(); + for bit in bits { + match bit { + Boolean::Is(ref bit) => { + all_constants = false; + + // Add the coeff * bit_gadget + lc = lc + (coeff, bit.get_variable()); + } + Boolean::Not(ref bit) => { + all_constants = false; + + // Add coeff * (1 - bit_gadget) = coeff * ONE - coeff * bit_gadget + lc = lc + (coeff, CS::one()) - (coeff, bit.get_variable()); + } + Boolean::Constant(bit) => { + if bit { + lc = lc + (coeff, CS::one()); + } + } + } + + coeff.double_in_place(); + } + + + // The value of the actual result is modulo 2 ^ $size + let modular_value = result_value.map(|v| v as <$gadget as Int>::IntegerType); + + if all_constants && modular_value.is_some() { + // We can just return a constant, rather than + // unpacking the result into allocated bits. + + return Ok(Self::constant(modular_value.unwrap())); + } + + // Storage area for the resulting bits + let mut result_bits = vec![]; + + // Allocate each bit_gadget of the result + let mut coeff = F::one(); + for i in 0..max_bits { + // get bit value + let mask = 1 << i as <$gadget as Int>::IntegerType; + + // Allocate the bit_gadget + let b = AllocatedBit::alloc(cs.ns(|| format!("result bit_gadget {}", i)), || { + result_value.map(|v| (v & mask) == mask).get() + })?; + + // Subtract this bit_gadget from the linear combination to ensure that the sums + // balance out + lc = lc - (coeff, b.get_variable()); + + result_bits.push(b.into()); + + coeff.double_in_place(); + } + + // Enforce that the linear combination equals zero + cs.enforce(|| "modular addition", |lc| lc, |lc| lc, |_| lc); + + // Discard carry bits we don't care about + result_bits.truncate(<$gadget as Int>::SIZE); + + Ok(Self { + bits: result_bits, + value: modular_value, + }) + } + } + )*) +} + +add_int_impl!(Int8 Int16 Int32 Int64 Int128); diff --git a/gadgets/src/signed_integer/arithmetic/div.rs b/gadgets/src/signed_integer/arithmetic/div.rs new file mode 100644 index 0000000000..eae60bd9d5 --- /dev/null +++ b/gadgets/src/signed_integer/arithmetic/div.rs @@ -0,0 +1,196 @@ +use crate::{ + arithmetic::{Add, Div, Neg, Sub}, + bits::ComparatorGadget, + errors::SignedIntegerError, + Int, + Int128, + Int16, + Int32, + Int64, + Int8, +}; + +use snarkos_models::{ + curves::PrimeField, + gadgets::{ + r1cs::ConstraintSystem, + utilities::{ + alloc::AllocGadget, + boolean::{AllocatedBit, Boolean}, + eq::EvaluateEqGadget, + select::CondSelectGadget, + }, + }, +}; + +macro_rules! div_int_impl { + ($($gadget:ident)*) => ($( + impl Div for $gadget { + type ErrorType = SignedIntegerError; + + fn div>( + &self, + mut cs: CS, + other: &Self + ) -> Result { + // N / D pseudocode: + // + // if D = 0 then error(DivisionByZeroException) end + // + // positive = msb(N) == msb(D) -- if msb's equal, return positive result + // + // Q := 0 -- Initialize quotient and remainder to zero + // R := 0 + // + // for i := n − 1 .. 0 do -- Where n is number of bits in N + // R := R << 1 -- Left-shift R by 1 bit + // R(0) := N(i) -- Set the least-significant bit of R equal to bit i of the numerator + // if R ≥ D then + // R := R − D + // Q(i) := 1 + // end + // end + // + // if positive then -- positive result + // Q + // else + // !Q -- negative result + + if other.eq(&Self::constant(0 as <$gadget as Int>::IntegerType)) { + return Err(SignedIntegerError::DivisionByZero); + } + + let is_constant = Boolean::constant(Self::result_is_constant(&self, &other)); + + let allocated_true = Boolean::from(AllocatedBit::alloc(&mut cs.ns(|| "true"), || Ok(true)).unwrap()); + let true_bit = Boolean::conditionally_select( + &mut cs.ns(|| "constant_or_allocated_true"), + &is_constant, + &Boolean::constant(true), + &allocated_true, + )?; + + let allocated_one = Self::alloc(&mut cs.ns(|| "one"), || Ok(1 as <$gadget as Int>::IntegerType))?; + let one = Self::conditionally_select( + &mut cs.ns(|| "constant_or_allocated_1"), + &is_constant, + &Self::constant(1 as <$gadget as Int>::IntegerType), + &allocated_one, + )?; + + let allocated_zero = Self::alloc(&mut cs.ns(|| "zero"), || Ok(0 as <$gadget as Int>::IntegerType))?; + let zero = Self::conditionally_select( + &mut cs.ns(|| "constant_or_allocated_0"), + &is_constant, + &Self::constant(0 as <$gadget as Int>::IntegerType), + &allocated_zero, + )?; + + let self_is_zero = Boolean::Constant(self.eq(&Self::constant(0 as <$gadget as Int>::IntegerType))); + + // If the most significant bits of both numbers are equal, the quotient will be positive + let a_msb = self.bits.last().unwrap(); + let b_msb = other.bits.last().unwrap(); + let positive = a_msb.evaluate_equal(cs.ns(|| "compare_msb"), &b_msb)?; + + // Get the absolute value of each number + let a_comp = self.neg(&mut cs.ns(|| "a_neg"))?; + let a = Self::conditionally_select( + &mut cs.ns(|| "a_abs"), + &a_msb, + &a_comp, + &self + )?; + + let b_comp = other.neg(&mut cs.ns(|| "b_neg"))?; + let b = Self::conditionally_select( + &mut cs.ns(|| "b_abs"), + &b_msb, + &b_comp, + &other, + )?; + + let mut q = zero.clone(); + let mut r = zero.clone(); + + let mut index = <$gadget as Int>::SIZE - 1 as usize; + let mut bit_value = (1 as <$gadget as Int>::IntegerType) << ((index - 1) as <$gadget as Int>::IntegerType); + + for (i, bit) in a.bits.iter().rev().enumerate().skip(1) { + + // Left shift remainder by 1 + r = r.add( + &mut cs.ns(|| format!("shift_left_{}", i)), + &r + )?; + + // Set the least-significant bit of remainder to bit i of the numerator + let r_new = r.add( + &mut cs.ns(|| format!("set_remainder_bit_{}", i)), + &one.clone(), + )?; + + r = Self::conditionally_select( + &mut cs.ns(|| format!("increment_or_remainder_{}", i)), + &bit, + &r_new, + &r + )?; + + let can_sub = r.greater_than_or_equal( + &mut cs.ns(|| format!("compare_remainder_{}", i)), + &b + )?; + + + let sub = r.sub( + &mut cs.ns(|| format!("subtract_divisor_{}", i)), + &b + ); + + + r = Self::conditionally_select( + &mut cs.ns(|| format!("subtract_or_same_{}", i)), + &can_sub, + &sub?, + &r + )?; + + index = index - 1; + + let mut q_new = q.clone(); + q_new.bits[index] = true_bit.clone(); + q_new.value = Some(q_new.value.unwrap() + bit_value); + + bit_value = (bit_value >> 1); + + q = Self::conditionally_select( + &mut cs.ns(|| format!("set_bit_or_same_{}", i)), + &can_sub, + &q_new, + &q, + )?; + + } + + let q_neg = q.neg(&mut cs.ns(|| "negate"))?; + + q = Self::conditionally_select( + &mut cs.ns(|| "positive or negative"), + &positive, + &q, + &q_neg, + )?; + + Ok(Self::conditionally_select( + &mut cs.ns(|| "self_or_quotient"), + &self_is_zero, + self, + &q + )?) + } + } + )*) +} + +div_int_impl!(Int8 Int16 Int32 Int64 Int128); diff --git a/gadgets/src/signed_integer/arithmetic/mod.rs b/gadgets/src/signed_integer/arithmetic/mod.rs new file mode 100644 index 0000000000..8ddd2e086e --- /dev/null +++ b/gadgets/src/signed_integer/arithmetic/mod.rs @@ -0,0 +1,18 @@ +#[macro_use] +pub mod add; +pub use self::add::*; + +pub mod div; +pub use self::div::*; + +pub mod mul; +pub use self::mul::*; + +pub mod neg; +pub use self::neg::*; + +pub mod pow; +pub use self::pow::*; + +pub mod sub; +pub use self::sub::*; diff --git a/gadgets/src/signed_integer/arithmetic/mul.rs b/gadgets/src/signed_integer/arithmetic/mul.rs new file mode 100644 index 0000000000..7c8eeb6831 --- /dev/null +++ b/gadgets/src/signed_integer/arithmetic/mul.rs @@ -0,0 +1,199 @@ +use crate::{ + arithmetic::Mul, + bits::{RippleCarryAdder, SignExtend}, + errors::SignedIntegerError, + Int, + Int128, + Int16, + Int32, + Int64, + Int8, +}; +use snarkos_models::{ + curves::{FpParameters, PrimeField}, + gadgets::{ + r1cs::{Assignment, ConstraintSystem, LinearCombination}, + utilities::{ + alloc::AllocGadget, + boolean::{AllocatedBit, Boolean}, + select::CondSelectGadget, + }, + }, +}; + +macro_rules! mul_int_impl { + ($($gadget: ident)*) => ($( + /// Bitwise multiplication of two signed integer objects. + impl Mul for $gadget { + + type ErrorType = SignedIntegerError; + + fn mul>(&self, mut cs: CS, other: &Self) -> Result { + // pseudocode: + // + // res = 0; + // for (i, bit) in other.bits.enumerate() { + // shifted_self = self << i; + // + // if bit { + // res += shifted_self; + // } + // } + // return res + + + // Conditionally select constant result + let is_constant = Boolean::constant(Self::result_is_constant(&self, &other)); + let allocated_false = Boolean::from(AllocatedBit::alloc(&mut cs.ns(|| "false"), || Ok(false)).unwrap()); + let false_bit = Boolean::conditionally_select( + &mut cs.ns(|| "constant_or_allocated_false"), + &is_constant, + &Boolean::constant(false), + &allocated_false, + )?; + + // Sign extend to double precision + let size = <$gadget as Int>::SIZE * 2; + + let a = Boolean::sign_extend(&self.bits, size); + let b = Boolean::sign_extend(&other.bits, size); + + let mut bits = vec![false_bit; size]; + + // Compute double and add algorithm + for (i, b_bit) in b.iter().enumerate() { + // double + let mut a_shifted = vec![false_bit; i]; + a_shifted.append(&mut a.clone()); + a_shifted.truncate(size); + + // conditionally add + let mut to_add = vec![]; + for (j, a_bit) in a_shifted.iter().enumerate() { + let selected_bit = Boolean::conditionally_select( + &mut cs.ns(|| format!("select product bit {} {}", i, j)), + b_bit, + a_bit, + &false_bit, + )?; + + to_add.push(selected_bit); + } + + bits = bits.add_bits( + &mut cs.ns(|| format!("add bit {}", i)), + &to_add + )?; + let _carry = bits.pop(); + } + + // Compute the maximum value of the sum + let max_bits = <$gadget as Int>::SIZE; + + // Truncate the bits to the size of the integer + bits.truncate(max_bits); + + // Make some arbitrary bounds for ourselves to avoid overflows + // in the scalar field + assert!(F::Params::MODULUS_BITS >= max_bits as u32); + + // Accumulate the value + let result_value = match (self.value, other.value) { + (Some(a), Some(b)) => { + // check for multiplication overflow here + let val = match a.checked_mul(b) { + Some(val) => val, + None => return Err(SignedIntegerError::Overflow) + }; + + Some(val) + }, + _ => { + // If any of the operands have unknown value, we won't + // know the value of the result + None + } + }; + + // This is a linear combination that we will enforce to be zero + let mut lc = LinearCombination::zero(); + + let mut all_constants = true; + + + // Iterate over each bit_gadget of result and add each bit to + // the linear combination + let mut coeff = F::one(); + for bit in bits { + match bit { + Boolean::Is(ref bit) => { + all_constants = false; + + // Add the coeff * bit_gadget + lc = lc + (coeff, bit.get_variable()); + } + Boolean::Not(ref bit) => { + all_constants = false; + + // Add coeff * (1 - bit_gadget) = coeff * ONE - coeff * bit_gadget + lc = lc + (coeff, CS::one()) - (coeff, bit.get_variable()); + } + Boolean::Constant(bit) => { + if bit { + lc = lc + (coeff, CS::one()); + } + } + } + + coeff.double_in_place(); + } + + // The value of the actual result is modulo 2 ^ $size + let modular_value = result_value.map(|v| v as <$gadget as Int>::IntegerType); + + if all_constants && modular_value.is_some() { + // We can just return a constant, rather than + // unpacking the result into allocated bits. + + return Ok(Self::constant(modular_value.unwrap())); + } + + // Storage area for the resulting bits + let mut result_bits = vec![]; + + // Allocate each bit_gadget of the result + let mut coeff = F::one(); + for i in 0..max_bits { + // get bit value + let mask = 1 << i as <$gadget as Int>::IntegerType; + + // Allocate the bit_gadget + let b = AllocatedBit::alloc(cs.ns(|| format!("result bit_gadget {}", i)), || { + result_value.map(|v| (v & mask) == mask).get() + })?; + + // Subtract this bit_gadget from the linear combination to ensure that the sums + // balance out + lc = lc - (coeff, b.get_variable()); + + result_bits.push(b.into()); + + coeff.double_in_place(); + } + + // Enforce that the linear combination equals zero + cs.enforce(|| "modular multiplication", |lc| lc, |lc| lc, |_| lc); + + // Discard carry bits we don't care about + result_bits.truncate(<$gadget as Int>::SIZE); + + Ok(Self { + bits: result_bits, + value: modular_value, + }) + } + } + )*) +} + +mul_int_impl!(Int8 Int16 Int32 Int64 Int128); diff --git a/gadgets/src/signed_integer/arithmetic/neg.rs b/gadgets/src/signed_integer/arithmetic/neg.rs new file mode 100644 index 0000000000..a5124d251f --- /dev/null +++ b/gadgets/src/signed_integer/arithmetic/neg.rs @@ -0,0 +1,36 @@ +use crate::{arithmetic::Neg, errors::SignedIntegerError, signed_integer::*}; + +use snarkos_models::{curves::PrimeField, gadgets::r1cs::ConstraintSystem}; + +macro_rules! neg_int_impl { + ($($gadget: ident)*) => ($( + impl Neg for $gadget { + type ErrorType = SignedIntegerError; + + fn neg>( + &self, + cs: CS + ) -> Result { + let value = match self.value { + Some(val) => { + match val.checked_neg() { + Some(val_neg) => Some(val_neg), + None => return Err(SignedIntegerError::Overflow) // -0 should fail + } + } + None => None, + }; + + // calculate two's complement + let bits = self.bits.neg(cs)?; + + Ok(Self { + bits, + value, + }) + } + } + )*) +} + +neg_int_impl!(Int8 Int16 Int32 Int64 Int128); diff --git a/gadgets/src/signed_integer/arithmetic/pow.rs b/gadgets/src/signed_integer/arithmetic/pow.rs new file mode 100644 index 0000000000..f3d13f4019 --- /dev/null +++ b/gadgets/src/signed_integer/arithmetic/pow.rs @@ -0,0 +1,86 @@ +use crate::{ + arithmetic::{Mul, Pow}, + errors::SignedIntegerError, + Int, + Int128, + Int16, + Int32, + Int64, + Int8, +}; + +use snarkos_models::{ + curves::PrimeField, + gadgets::{ + r1cs::ConstraintSystem, + utilities::{alloc::AllocGadget, boolean::Boolean, select::CondSelectGadget}, + }, +}; + +macro_rules! pow_int_impl { + ($($gadget:ty)*) => ($( + impl Pow for $gadget { + type ErrorType = SignedIntegerError; + + fn pow>(&self, mut cs: CS, other: &Self) -> Result { + // let mut res = Self::one(); + // + // let mut found_one = false; + // + // for i in BitIterator::new(exp) { + // if !found_one { + // if i { + // found_one = true; + // } else { + // continue; + // } + // } + // + // res.square_in_place(); + // + // if i { + // res *= self; + // } + // } + // res + + let is_constant = Boolean::constant(Self::result_is_constant(&self, &other)); + let one_const = Self::constant(1 as <$gadget as Int>::IntegerType); + let one_alloc = Self::alloc(&mut cs.ns(|| "allocated_1"), || Ok(1 as <$gadget as Int>::IntegerType))?; + let mut result = Self::conditionally_select( + &mut cs.ns(|| "constant_or_allocated"), + &is_constant, + &one_const, + &one_alloc, + )?; + + for (i, bit) in other.bits.iter().rev().enumerate() { + let found_one = Boolean::constant(result.eq(&one_const)); + let cond1 = Boolean::and(cs.ns(|| format!("found_one_{}", i)), &bit.not(), &found_one)?; + let square = result.mul(cs.ns(|| format!("square_{}", i)), &result).unwrap(); + + result = Self::conditionally_select( + &mut cs.ns(|| format!("result_or_square_{}", i)), + &cond1, + &result, + &square, + )?; + + let mul_by_self = result + .mul(cs.ns(|| format!("multiply_by_self_{}", i)), &self); + + result = Self::conditionally_select( + &mut cs.ns(|| format!("mul_by_self_or_result_{}", i)), + &bit, + &mul_by_self?, + &result, + )?; + + } + Ok(result) + } + } + )*) +} + +pow_int_impl!(Int8 Int16 Int32 Int64 Int128); diff --git a/gadgets/src/signed_integer/arithmetic/sub.rs b/gadgets/src/signed_integer/arithmetic/sub.rs new file mode 100644 index 0000000000..cbc7af9aed --- /dev/null +++ b/gadgets/src/signed_integer/arithmetic/sub.rs @@ -0,0 +1,28 @@ +use crate::{ + arithmetic::{Add, Neg, Sub}, + errors::SignedIntegerError, + Int128, + Int16, + Int32, + Int64, + Int8, +}; +use snarkos_models::{curves::PrimeField, gadgets::r1cs::ConstraintSystem}; + +macro_rules! sub_int_impl { + ($($gadget: ident)*) => ($( + impl Sub for $gadget { + type ErrorType = SignedIntegerError; + + fn sub>(&self, mut cs: CS, other: &Self) -> Result { + // Negate other + let other_neg = other.neg(cs.ns(|| format!("negate")))?; + + // self + negated other + self.add(cs.ns(|| format!("add_complement")), &other_neg) + } + } + )*) +} + +sub_int_impl!(Int8 Int16 Int32 Int64 Int128); diff --git a/gadgets/src/signed_integer/int_impl.rs b/gadgets/src/signed_integer/int_impl.rs new file mode 100644 index 0000000000..97173b6987 --- /dev/null +++ b/gadgets/src/signed_integer/int_impl.rs @@ -0,0 +1,90 @@ +use snarkos_models::gadgets::utilities::boolean::Boolean; + +use std::fmt::Debug; + +pub trait Int: Debug + Clone { + type IntegerType; + const SIZE: usize; + + fn one() -> Self; + + fn zero() -> Self; + + /// Returns true if all bits in this `Int` are constant + fn is_constant(&self) -> bool; + + /// Returns true if both `Int` objects have constant bits + fn result_is_constant(first: &Self, second: &Self) -> bool { + first.is_constant() && second.is_constant() + } +} + +/// Implements the base struct for a signed integer gadget +macro_rules! int_impl { + ($name: ident, $type_: ty, $size: expr) => { + #[derive(Clone, Debug)] + pub struct $name { + pub bits: Vec, + pub value: Option<$type_>, + } + + impl $name { + pub fn constant(value: $type_) -> Self { + let mut bits = Vec::with_capacity($size); + + for i in 0..$size { + // shift value by i + let mask = 1 << i as $type_; + let result = value & mask; + + // If last bit is one, push one. + if result == mask { + bits.push(Boolean::constant(true)) + } else { + bits.push(Boolean::constant(false)) + } + } + + Self { + bits, + value: Some(value), + } + } + } + + impl Int for $name { + type IntegerType = $type_; + + const SIZE: usize = $size; + + fn one() -> Self { + Self::constant(1 as $type_) + } + + fn zero() -> Self { + Self::constant(0 as $type_) + } + + fn is_constant(&self) -> bool { + let mut constant = true; + + // If any bits of self are allocated bits, return false + for bit in &self.bits { + match *bit { + Boolean::Is(ref _bit) => constant = false, + Boolean::Not(ref _bit) => constant = false, + Boolean::Constant(_bit) => {} + } + } + + constant + } + } + }; +} + +int_impl!(Int8, i8, 8); +int_impl!(Int16, i16, 16); +int_impl!(Int32, i32, 32); +int_impl!(Int64, i64, 64); +int_impl!(Int128, i128, 128); diff --git a/gadgets/src/signed_integer/mod.rs b/gadgets/src/signed_integer/mod.rs new file mode 100644 index 0000000000..99a2192182 --- /dev/null +++ b/gadgets/src/signed_integer/mod.rs @@ -0,0 +1,13 @@ +#[macro_use] + +pub mod arithmetic; +pub use self::arithmetic::*; + +pub mod int_impl; +pub use self::int_impl::*; + +pub mod relational; +pub use self::relational::*; + +pub mod utilities; +pub use self::utilities::*; diff --git a/gadgets/src/signed_integer/relational/cmp.rs b/gadgets/src/signed_integer/relational/cmp.rs new file mode 100644 index 0000000000..57fae96f0e --- /dev/null +++ b/gadgets/src/signed_integer/relational/cmp.rs @@ -0,0 +1,82 @@ +use crate::{ + bits::{ComparatorGadget, EvaluateLtGadget}, + Int128, + Int16, + Int32, + Int64, + Int8, +}; + +use snarkos_errors::gadgets::SynthesisError; +use snarkos_models::{ + curves::PrimeField, + gadgets::{ + r1cs::ConstraintSystem, + utilities::{boolean::Boolean, select::CondSelectGadget}, + }, +}; +use std::cmp::Ordering; + +macro_rules! cmp_gadget_impl { + ($($gadget: ident)*) => ($( + /* Bitwise less than comparison of two signed integers */ + impl EvaluateLtGadget for $gadget { + fn less_than>( + &self, + mut cs: CS, + other: &Self + ) -> Result { + + let mut result = Boolean::constant(true); + let mut all_equal = Boolean::constant(true); + + // msb -> lsb + for (i, (a, b)) in self + .bits + .iter() + .rev() + .zip(other.bits.iter().rev()) + .enumerate() + { + + // check msb signed bit + let less = if i == 0 { + // a == 1 & b == 0 + Boolean::and(cs.ns(|| format!("a and not b [{}]", i)), a, &b.not())? + } else { + // a == 0 & b == 1 + Boolean::and(cs.ns(|| format!("not a and b [{}]", i)), &a.not(), b)? + }; + + // a == b = !(a ^ b) + let not_equal = Boolean::xor(cs.ns(|| format!("a XOR b [{}]", i)), a, b)?; + let equal = not_equal.not(); + + // evaluate a <= b + let less_or_equal = Boolean::or(cs.ns(|| format!("less or equal [{}]", i)), &less, &equal)?; + + // If `all_equal` is `true`, sets `result` to `less_or_equal`. Else, sets `result` to `result`. + result = Boolean::conditionally_select(cs.ns(|| format!("select bit [{}]", i)), &all_equal, &less_or_equal, &result)?; + + // keep track of equal bits + all_equal = Boolean::and(cs.ns(|| format!("accumulate equal [{}]", i)), &all_equal, &equal)?; + } + + result = Boolean::and(cs.ns(|| format!("false if all equal")), &result, &all_equal.not())?; + + Ok(result) + } + } + + /* Bitwise comparison of two unsigned integers */ + impl ComparatorGadget for $gadget {} + + impl PartialOrd for $gadget { + fn partial_cmp(&self, other: &Self) -> Option { + Option::from(self.value.cmp(&other.value)) + } + } + )*) +} + +cmp_gadget_impl!(Int8 Int16 Int32 Int64 Int128); diff --git a/gadgets/src/signed_integer/relational/eq.rs b/gadgets/src/signed_integer/relational/eq.rs new file mode 100644 index 0000000000..b1047a7114 --- /dev/null +++ b/gadgets/src/signed_integer/relational/eq.rs @@ -0,0 +1,48 @@ +use crate::{Int, Int128, Int16, Int32, Int64, Int8}; + +use snarkos_errors::gadgets::SynthesisError; +use snarkos_models::{ + curves::PrimeField, + gadgets::{ + r1cs::ConstraintSystem, + utilities::{boolean::Boolean, eq::EvaluateEqGadget}, + }, +}; + +macro_rules! eq_gadget_impl { + ($($gadget: ident)*) => ($( + impl EvaluateEqGadget for $gadget { + fn evaluate_equal>( + &self, + mut cs: CS, + other: &Self + ) -> Result { + let mut result = Boolean::constant(true); + for (i, (a, b)) in self.bits.iter().zip(&other.bits).enumerate() { + let equal = a.evaluate_equal( + &mut cs.ns(|| format!("{} evaluate equality for {}-th bit", <$gadget as Int>::SIZE, i)), + b, + )?; + + result = Boolean::and( + &mut cs.ns(|| format!("{} and result for {}-th bit", <$gadget as Int>::SIZE, i)), + &equal, + &result, + )?; + } + + Ok(result) + } + } + + impl PartialEq for $gadget { + fn eq(&self, other: &Self) -> bool { + !self.value.is_none() && !other.value.is_none() && self.value == other.value + } + } + + impl Eq for $gadget {} + )*) +} + +eq_gadget_impl!(Int8 Int16 Int32 Int64 Int128); diff --git a/gadgets/src/signed_integer/relational/mod.rs b/gadgets/src/signed_integer/relational/mod.rs new file mode 100644 index 0000000000..977eaccd49 --- /dev/null +++ b/gadgets/src/signed_integer/relational/mod.rs @@ -0,0 +1,6 @@ +#[macro_use] +pub mod eq; +pub use self::eq::*; + +pub mod cmp; +pub use self::cmp::*; diff --git a/gadgets/src/signed_integer/utilities/alloc.rs b/gadgets/src/signed_integer/utilities/alloc.rs new file mode 100644 index 0000000000..6958fd58b0 --- /dev/null +++ b/gadgets/src/signed_integer/utilities/alloc.rs @@ -0,0 +1,102 @@ +use crate::{Int, Int128, Int16, Int32, Int64, Int8}; + +use core::borrow::Borrow; +use snarkos_errors::gadgets::SynthesisError; +use snarkos_models::{ + curves::Field, + gadgets::{ + r1cs::ConstraintSystem, + utilities::{ + alloc::AllocGadget, + boolean::{AllocatedBit, Boolean}, + }, + }, +}; + +macro_rules! alloc_int_impl { + ($($gadget: ident)*) => ($( + impl AllocGadget<<$gadget as Int>::IntegerType, F> for $gadget { + fn alloc< + Fn: FnOnce() -> Result, + T: Borrow<<$gadget as Int>::IntegerType>, + CS: ConstraintSystem + >( + mut cs: CS, + value_gen: Fn, + ) -> Result { + let value = value_gen().map(|val| *val.borrow()); + let values = match value { + Ok(mut val) => { + let mut v = Vec::with_capacity(<$gadget as Int>::SIZE); + + for _ in 0..<$gadget as Int>::SIZE { + v.push(Some(val & 1 == 1)); + val >>= 1; + } + + v + } + _ => vec![None; <$gadget as Int>::SIZE], + }; + + let bits = values + .into_iter() + .enumerate() + .map(|(i, v)| { + Ok(Boolean::from(AllocatedBit::alloc( + &mut cs.ns(|| format!("allocated bit_gadget {}", i)), + || v.ok_or(SynthesisError::AssignmentMissing), + )?)) + }) + .collect::, SynthesisError>>()?; + + Ok(Self { + bits, + value: value.ok(), + }) + } + + fn alloc_input< + Fn: FnOnce() -> Result, + T: Borrow<<$gadget as Int>::IntegerType>, + CS: ConstraintSystem + >( + mut cs: CS, + value_gen: Fn, + ) -> Result { + let value = value_gen().map(|val| *val.borrow()); + let values = match value { + Ok(mut val) => { + let mut v = Vec::with_capacity(<$gadget as Int>::SIZE); + + for _ in 0..<$gadget as Int>::SIZE { + v.push(Some(val & 1 == 1)); + val >>= 1; + } + + v + } + _ => vec![None; <$gadget as Int>::SIZE], + }; + + let bits = values + .into_iter() + .enumerate() + .map(|(i, v)| { + Ok(Boolean::from(AllocatedBit::alloc( + &mut cs.ns(|| format!("allocated bit_gadget {}", i)), + || v.ok_or(SynthesisError::AssignmentMissing), + )?)) + }) + .collect::, SynthesisError>>()?; + + Ok(Self { + bits, + value: value.ok(), + }) + } + } + )*) +} + +alloc_int_impl!(Int8 Int16 Int32 Int64 Int128); diff --git a/gadgets/src/signed_integer/utilities/eq.rs b/gadgets/src/signed_integer/utilities/eq.rs new file mode 100644 index 0000000000..594c495788 --- /dev/null +++ b/gadgets/src/signed_integer/utilities/eq.rs @@ -0,0 +1,39 @@ +use crate::signed_integer::*; + +use snarkos_errors::gadgets::SynthesisError; +use snarkos_models::{ + curves::PrimeField, + gadgets::{ + r1cs::ConstraintSystem, + utilities::{boolean::Boolean, eq::ConditionalEqGadget}, + }, +}; + +macro_rules! cond_eq_int_impl { + ($($gadget: ident),*) => ($( + impl ConditionalEqGadget for $gadget { + fn conditional_enforce_equal>( + &self, + mut cs: CS, + other: &Self, + condition: &Boolean, + ) -> Result<(), SynthesisError> { + for (i, (a, b)) in self.bits.iter().zip(&other.bits).enumerate() { + a.conditional_enforce_equal( + &mut cs.ns(|| format!("{} equality check for the {}-th bit", <$gadget as Int>::SIZE, i)), + b, + condition, + )?; + } + + Ok(()) + } + + fn cost() -> usize { + <$gadget as Int>::SIZE * >::cost() + } + } + )*) +} + +cond_eq_int_impl!(Int8, Int16, Int32, Int64, Int128); diff --git a/gadgets/src/signed_integer/utilities/mod.rs b/gadgets/src/signed_integer/utilities/mod.rs new file mode 100644 index 0000000000..8bc79c27f7 --- /dev/null +++ b/gadgets/src/signed_integer/utilities/mod.rs @@ -0,0 +1,9 @@ +#[macro_use] +pub mod alloc; +pub use self::alloc::*; + +pub mod eq; +pub use self::eq::*; + +pub mod select; +pub use self::select::*; diff --git a/gadgets/src/signed_integer/utilities/select.rs b/gadgets/src/signed_integer/utilities/select.rs new file mode 100644 index 0000000000..de93156fbb --- /dev/null +++ b/gadgets/src/signed_integer/utilities/select.rs @@ -0,0 +1,68 @@ +use crate::signed_integer::*; + +use snarkos_errors::gadgets::SynthesisError; +use snarkos_models::{ + curves::PrimeField, + gadgets::{ + r1cs::{Assignment, ConstraintSystem}, + utilities::{alloc::AllocGadget, boolean::Boolean, eq::EqGadget, select::CondSelectGadget}, + }, +}; + +macro_rules! select_int_impl { + ($($gadget: ident)*) => ($( + impl CondSelectGadget for $gadget { + fn conditionally_select> ( + mut cs: CS, + cond: &Boolean, + first: &Self, + second: &Self, + ) -> Result { + if let Boolean::Constant(cond) = *cond { + if cond { + Ok(first.clone()) + } else { + Ok(second.clone()) + } + } else { + let result_val = cond.get_value().and_then(|c| { + if c { + first.value + } else { + second.value + } + }); + + let result = Self::alloc(cs.ns(|| "cond_select_result"), || result_val.get().map(|v| v))?; + + let expected_bits = first + .bits + .iter() + .zip(&second.bits) + .enumerate() + .map(|(i, (a, b))| { + Boolean::conditionally_select( + &mut cs.ns(|| format!("{}_cond_select_{}", <$gadget as Int>::SIZE, i)), + cond, + a, + b, + ).unwrap() + }) + .collect::>(); + + for (i, (actual, expected)) in result.bits.iter().zip(expected_bits.iter()).enumerate() { + actual.enforce_equal(&mut cs.ns(|| format!("selected_result_bit_{}", i)), expected)?; + } + + Ok(result) + } + } + + fn cost() -> usize { + unimplemented!(); + } + } + )*) +} + +select_int_impl!(Int8 Int16 Int32 Int64 Int128); diff --git a/gadgets/tests/mod.rs b/gadgets/tests/mod.rs new file mode 100644 index 0000000000..3a4d43aad7 --- /dev/null +++ b/gadgets/tests/mod.rs @@ -0,0 +1,2 @@ +pub mod signed_integer; +pub use self::signed_integer::*; diff --git a/gadgets/tests/signed_integer/i128.rs b/gadgets/tests/signed_integer/i128.rs new file mode 100644 index 0000000000..72978e8860 --- /dev/null +++ b/gadgets/tests/signed_integer/i128.rs @@ -0,0 +1,104 @@ +use leo_gadgets::{arithmetic::Add, Int128}; +use snarkos_models::{ + curves::{One, Zero}, + gadgets::{ + r1cs::{ConstraintSystem, Fr, TestConstraintSystem}, + utilities::{alloc::AllocGadget, boolean::Boolean}, + }, +}; + +use rand::{Rng, SeedableRng}; +use rand_xorshift::XorShiftRng; + +fn check_all_constant_bits(mut expected: i128, actual: Int128) { + for b in actual.bits.iter() { + match b { + &Boolean::Is(_) => panic!(), + &Boolean::Not(_) => panic!(), + &Boolean::Constant(b) => { + assert!(b == (expected & 1 == 1)); + } + } + + expected >>= 1; + } +} + +fn check_all_allocated_bits(mut expected: i128, actual: Int128) { + for b in actual.bits.iter() { + match b { + &Boolean::Is(ref b) => { + assert!(b.get_value().unwrap() == (expected & 1 == 1)); + } + &Boolean::Not(ref b) => { + assert!(!b.get_value().unwrap() == (expected & 1 == 1)); + } + &Boolean::Constant(_) => unreachable!(), + } + + expected >>= 1; + } +} + +#[test] +fn test_int128_add_constants() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let mut cs = TestConstraintSystem::::new(); + + let a: i128 = rng.gen(); + let b: i128 = rng.gen(); + + let a_bit = Int128::constant(a); + let b_bit = Int128::constant(b); + + let expected = match a.checked_add(b) { + Some(valid) => valid, + None => continue, + }; + + let r = a_bit.add(cs.ns(|| "addition"), &b_bit).unwrap(); + + assert!(r.value == Some(expected)); + + check_all_constant_bits(expected, r); + } +} + +#[test] +fn test_int128_add() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..100 { + let mut cs = TestConstraintSystem::::new(); + + let a: i128 = rng.gen(); + let b: i128 = rng.gen(); + + let expected = match a.checked_add(b) { + Some(valid) => valid, + None => continue, + }; + + let a_bit = Int128::alloc(cs.ns(|| "a_bit"), || Ok(a)).unwrap(); + let b_bit = Int128::alloc(cs.ns(|| "b_bit"), || Ok(b)).unwrap(); + + let r = a_bit.add(cs.ns(|| "addition"), &b_bit).unwrap(); + + assert!(cs.is_satisfied()); + + assert!(r.value == Some(expected)); + + check_all_allocated_bits(expected, r); + + // Flip a bit_gadget and see if the addition constraint still works + if cs.get("addition/result bit_gadget 0/boolean").is_zero() { + cs.set("addition/result bit_gadget 0/boolean", Fr::one()); + } else { + cs.set("addition/result bit_gadget 0/boolean", Fr::zero()); + } + + assert!(!cs.is_satisfied()); + } +} diff --git a/gadgets/tests/signed_integer/i8.rs b/gadgets/tests/signed_integer/i8.rs new file mode 100644 index 0000000000..3ba64d99d1 --- /dev/null +++ b/gadgets/tests/signed_integer/i8.rs @@ -0,0 +1,406 @@ +use leo_gadgets::{arithmetic::*, Int8}; + +use snarkos_models::{ + curves::{One, Zero}, + gadgets::{ + r1cs::{ConstraintSystem, Fr, TestConstraintSystem}, + utilities::{alloc::AllocGadget, boolean::Boolean}, + }, +}; + +use rand::{Rng, SeedableRng}; +use rand_xorshift::XorShiftRng; +use std::i8; + +fn check_all_constant_bits(expected: i8, actual: Int8) { + for (i, b) in actual.bits.iter().enumerate() { + // shift value by i + let mask = 1 << i as i8; + let result = expected & mask; + + match b { + &Boolean::Is(_) => panic!(), + &Boolean::Not(_) => panic!(), + &Boolean::Constant(b) => { + let bit = result == mask; + assert_eq!(b, bit); + } + } + } +} + +fn check_all_allocated_bits(expected: i8, actual: Int8) { + for (i, b) in actual.bits.iter().enumerate() { + // shift value by i + let mask = 1 << i as i8; + let result = expected & mask; + + match b { + &Boolean::Is(ref b) => { + let bit = result == mask; + assert_eq!(b.get_value().unwrap(), bit); + } + &Boolean::Not(ref b) => { + let bit = result == mask; + assert_eq!(!b.get_value().unwrap(), bit); + } + &Boolean::Constant(_) => unreachable!(), + } + } +} + +#[test] +fn test_int8_constant_and_alloc() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let mut cs = TestConstraintSystem::::new(); + + let a: i8 = rng.gen(); + + let a_const = Int8::constant(a); + + assert!(a_const.value == Some(a)); + + check_all_constant_bits(a, a_const); + + let a_bit = Int8::alloc(cs.ns(|| "a_bit"), || Ok(a)).unwrap(); + + assert!(cs.is_satisfied()); + assert!(a_bit.value == Some(a)); + + check_all_allocated_bits(a, a_bit); + } +} + +#[test] +fn test_int8_add_constants() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let mut cs = TestConstraintSystem::::new(); + + let a: i8 = rng.gen(); + let b: i8 = rng.gen(); + + let a_bit = Int8::constant(a); + let b_bit = Int8::constant(b); + + let expected = match a.checked_add(b) { + Some(valid) => valid, + None => continue, + }; + + let r = a_bit.add(cs.ns(|| "addition"), &b_bit).unwrap(); + + assert!(r.value == Some(expected)); + + check_all_constant_bits(expected, r); + } +} + +#[test] +fn test_int8_add() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let mut cs = TestConstraintSystem::::new(); + + let a: i8 = rng.gen(); + let b: i8 = rng.gen(); + + let expected = match a.checked_add(b) { + Some(valid) => valid, + None => continue, + }; + + let a_bit = Int8::alloc(cs.ns(|| "a_bit"), || Ok(a)).unwrap(); + let b_bit = Int8::alloc(cs.ns(|| "b_bit"), || Ok(b)).unwrap(); + + let r = a_bit.add(cs.ns(|| "addition"), &b_bit).unwrap(); + + assert!(cs.is_satisfied()); + + assert!(r.value == Some(expected)); + + check_all_allocated_bits(expected, r); + + // Flip a bit_gadget and see if the addition constraint still works + if cs.get("addition/result bit_gadget 0/boolean").is_zero() { + cs.set("addition/result bit_gadget 0/boolean", Fr::one()); + } else { + cs.set("addition/result bit_gadget 0/boolean", Fr::zero()); + } + + assert!(!cs.is_satisfied()); + } +} + +#[test] +fn test_int8_sub_constants() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let mut cs = TestConstraintSystem::::new(); + + let a: i8 = rng.gen(); + let b: i8 = rng.gen(); + + if b.checked_neg().is_none() { + // negate with overflows will fail: -128 + continue; + } + let expected = match a.checked_sub(b) { + // subtract with overflow will fail: -0 + Some(valid) => valid, + None => continue, + }; + + let a_bit = Int8::constant(a); + let b_bit = Int8::constant(b); + + let r = a_bit.sub(cs.ns(|| "subtraction"), &b_bit).unwrap(); + + assert!(r.value == Some(expected)); + + check_all_constant_bits(expected, r); + } +} + +#[test] +fn test_int8_sub() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let mut cs = TestConstraintSystem::::new(); + + let a: i8 = rng.gen(); + let b: i8 = rng.gen(); + + if b.checked_neg().is_none() { + // negate with overflows will fail: -128 + continue; + } + let expected = match a.checked_sub(b) { + // subtract with overflow will fail: -0 + Some(valid) => valid, + None => continue, + }; + + let a_bit = Int8::alloc(cs.ns(|| "a_bit"), || Ok(a)).unwrap(); + let b_bit = Int8::alloc(cs.ns(|| "b_bit"), || Ok(b)).unwrap(); + + let r = a_bit.sub(cs.ns(|| "subtraction"), &b_bit).unwrap(); + + assert!(cs.is_satisfied()); + + assert!(r.value == Some(expected)); + + check_all_allocated_bits(expected, r); + + // Flip a bit_gadget and see if the subtraction constraint still works + if cs + .get("subtraction/add_complement/result bit_gadget 0/boolean") + .is_zero() + { + cs.set("subtraction/add_complement/result bit_gadget 0/boolean", Fr::one()); + } else { + cs.set("subtraction/add_complement/result bit_gadget 0/boolean", Fr::zero()); + } + + assert!(!cs.is_satisfied()); + } +} + +#[test] +fn test_int8_mul_constants() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let mut cs = TestConstraintSystem::::new(); + + let a: i8 = rng.gen(); + let b: i8 = rng.gen(); + + let expected = match a.checked_mul(b) { + Some(valid) => valid, + None => continue, + }; + + let a_bit = Int8::constant(a); + let b_bit = Int8::constant(b); + + let r = a_bit.mul(cs.ns(|| "multiplication"), &b_bit).unwrap(); + + assert!(r.value == Some(expected)); + + check_all_constant_bits(expected, r); + } +} + +#[test] +fn test_int8_mul() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let mut cs = TestConstraintSystem::::new(); + + let a: i8 = rng.gen(); + let b: i8 = rng.gen(); + + let expected = match a.checked_mul(b) { + Some(valid) => valid, + None => continue, + }; + + let a_bit = Int8::alloc(cs.ns(|| "a_bit"), || Ok(a)).unwrap(); + let b_bit = Int8::alloc(cs.ns(|| "b_bit"), || Ok(b)).unwrap(); + + let r = a_bit.mul(cs.ns(|| "multiplication"), &b_bit).unwrap(); + + assert!(cs.is_satisfied()); + + assert!(r.value == Some(expected)); + + check_all_allocated_bits(expected, r); + + // Flip a bit_gadget and see if the multiplication constraint still works + if cs.get("multiplication/result bit_gadget 0/boolean").is_zero() { + cs.set("multiplication/result bit_gadget 0/boolean", Fr::one()); + } else { + cs.set("multiplication/result bit_gadget 0/boolean", Fr::zero()); + } + + assert!(!cs.is_satisfied()); + } +} + +#[test] +fn test_int8_div_constants() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let mut cs = TestConstraintSystem::::new(); + + let a: i8 = rng.gen_range(-127i8, i8::MAX); + let b: i8 = rng.gen_range(-127i8, i8::MAX); + + let expected = match a.checked_div(b) { + Some(valid) => valid, + None => continue, + }; + + let a_bit = Int8::constant(a); + let b_bit = Int8::constant(b); + + let r = a_bit.div(cs.ns(|| "division"), &b_bit).unwrap(); + + assert!(r.value == Some(expected)); + + check_all_constant_bits(expected, r); + } +} + +#[test] +fn test_int8_div() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..100 { + let mut cs = TestConstraintSystem::::new(); + + let a: i8 = rng.gen_range(-127i8, i8::MAX); + let b: i8 = rng.gen_range(-127i8, i8::MAX); + + let expected = match a.checked_div(b) { + Some(valid) => valid, + None => continue, + }; + + let a_bit = Int8::alloc(cs.ns(|| "a_bit"), || Ok(a)).unwrap(); + let b_bit = Int8::alloc(cs.ns(|| "b_bit"), || Ok(b)).unwrap(); + + let r = a_bit.div(cs.ns(|| "division"), &b_bit).unwrap(); + + assert!(cs.is_satisfied()); + + assert!(r.value == Some(expected)); + + check_all_allocated_bits(expected, r); + } +} + +#[test] +fn test_int8_pow_constants() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for _ in 0..1000 { + let mut cs = TestConstraintSystem::::new(); + + let a: i8 = rng.gen(); + let b: i8 = rng.gen(); + + let a_bit = Int8::constant(a); + let b_bit = Int8::constant(b); + + let expected = match a.checked_pow(b as u32) { + Some(valid) => valid, + None => continue, + }; + + let r = a_bit.pow(cs.ns(|| "exponentiation"), &b_bit).unwrap(); + + assert!(r.value == Some(expected)); + + check_all_constant_bits(expected, r); + } +} + +#[test] +fn test_int8_pow() { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + + for i in 0..10 { + let mut cs = TestConstraintSystem::::new(); + + // Test small ranges that we know won't overflow first + let (a, b): (i8, i8) = if i < 50 { + (rng.gen_range(-4, 4), rng.gen_range(0, 4)) + } else { + (rng.gen(), rng.gen()) + }; + + let expected = match a.checked_pow(b as u32) { + Some(valid) => valid, + None => continue, + }; + + let a_bit = Int8::alloc(cs.ns(|| "a_bit"), || Ok(a)).unwrap(); + let b_bit = Int8::alloc(cs.ns(|| "b_bit"), || Ok(b)).unwrap(); + + let r = a_bit.pow(cs.ns(|| "exponentiation"), &b_bit).unwrap(); + + assert!(cs.is_satisfied()); + + assert!(r.value == Some(expected)); + + check_all_allocated_bits(expected, r); + + // Flip a bit_gadget and see if the exponentiation constraint still works + if cs + .get("exponentiation/multiply_by_self_0/result bit_gadget 0/boolean") + .is_zero() + { + cs.set( + "exponentiation/multiply_by_self_0/result bit_gadget 0/boolean", + Fr::one(), + ); + } else { + cs.set( + "exponentiation/multiply_by_self_0/result bit_gadget 0/boolean", + Fr::zero(), + ); + } + + assert!(!cs.is_satisfied()); + } +} diff --git a/gadgets/tests/signed_integer/mod.rs b/gadgets/tests/signed_integer/mod.rs new file mode 100644 index 0000000000..e59b29ecac --- /dev/null +++ b/gadgets/tests/signed_integer/mod.rs @@ -0,0 +1,2 @@ +pub mod i128; +pub mod i8; diff --git a/leo-inputs/src/leo-inputs.pest b/leo-inputs/src/leo-inputs.pest index ea613aece0..601e0693ec 100644 --- a/leo-inputs/src/leo-inputs.pest +++ b/leo-inputs/src/leo-inputs.pest @@ -2,7 +2,24 @@ // Declared in common/identifier.rs identifier = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* } -protected_name = { "let" | "for"| "if" | "else" | "as" | "return" } +protected_name = { + "address" + | "as" + | "const" + | "else" + | "false" + | "function" + | "for" + | "if" + | "import" + | "in" + | "let" + | "mut" + | "return" + | "static" + | "test" + | "true" + } // Declared in common/line_end.rs LINE_END = { ";" ~ NEWLINE* } @@ -20,13 +37,27 @@ type_integer = { | type_u32 | type_u64 | type_u128 + | type_i8 + | type_i16 + | type_i32 + | type_i64 + | type_i128 } + +// Declared in types/integer_type.rs type_u8 = { "u8" } type_u16 = { "u16" } type_u32 = { "u32" } type_u64 = { "u64" } type_u128 = { "u128" } +// Declared in types/integer_type.rs +type_i8 = { "i8" } +type_i16 = { "i16" } +type_i32 = { "i32" } +type_i64 = { "i64" } +type_i128 = { "i128" } + // Declared in types/field_type.rs type_field = { "field" } @@ -58,7 +89,7 @@ value = { } // 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 value_implicit = { value_number } diff --git a/leo-inputs/src/types/integer_type.rs b/leo-inputs/src/types/integer_type.rs index ed2b520d1c..c49cb11562 100644 --- a/leo-inputs/src/types/integer_type.rs +++ b/leo-inputs/src/types/integer_type.rs @@ -10,8 +10,16 @@ pub enum IntegerType { U32Type(U32Type), U64Type(U64Type), U128Type(U128Type), + + I8Type(I8Type), + I16Type(I16Type), + I32Type(I32Type), + I64Type(I64Type), + I128Type(I128Type), } +// Unsigned + #[derive(Clone, Debug, FromPest, PartialEq, Eq)] #[pest_ast(rule(Rule::type_u8))] pub struct U8Type {} @@ -32,6 +40,28 @@ pub struct U64Type {} #[pest_ast(rule(Rule::type_u128))] pub struct U128Type {} +// Signed + +#[derive(Clone, Debug, FromPest, PartialEq, Eq)] +#[pest_ast(rule(Rule::type_i8))] +pub struct I8Type {} + +#[derive(Clone, Debug, FromPest, PartialEq, Eq)] +#[pest_ast(rule(Rule::type_i16))] +pub struct I16Type {} + +#[derive(Clone, Debug, FromPest, PartialEq, Eq)] +#[pest_ast(rule(Rule::type_i32))] +pub struct I32Type {} + +#[derive(Clone, Debug, FromPest, PartialEq, Eq)] +#[pest_ast(rule(Rule::type_i64))] +pub struct I64Type {} + +#[derive(Clone, Debug, FromPest, PartialEq, Eq)] +#[pest_ast(rule(Rule::type_i128))] +pub struct I128Type {} + impl std::fmt::Display for IntegerType { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { @@ -40,6 +70,12 @@ impl std::fmt::Display for IntegerType { IntegerType::U32Type(_) => write!(f, "u32"), IntegerType::U64Type(_) => write!(f, "u64"), IntegerType::U128Type(_) => write!(f, "u128"), + + IntegerType::I8Type(_) => write!(f, "i8"), + IntegerType::I16Type(_) => write!(f, "i16"), + IntegerType::I32Type(_) => write!(f, "i32"), + IntegerType::I64Type(_) => write!(f, "i64"), + IntegerType::I128Type(_) => write!(f, "i128"), } } } diff --git a/types/src/inputs/input_value.rs b/types/src/inputs/input_value.rs index a731c7d1f1..6faf19efce 100644 --- a/types/src/inputs/input_value.rs +++ b/types/src/inputs/input_value.rs @@ -14,7 +14,7 @@ pub enum InputValue { Boolean(bool), Field(String), Group(String), - Integer(IntegerType, u128), + Integer(IntegerType, String), Array(Vec), } @@ -29,8 +29,7 @@ impl InputValue { } fn from_number(integer_type: IntegerType, number: NumberValue) -> Result { - let integer = number.value.parse::()?; - Ok(InputValue::Integer(integer_type, integer)) + Ok(InputValue::Integer(integer_type, number.value)) } fn from_group(group: GroupValue) -> Self { diff --git a/types/src/types/integer_type.rs b/types/src/types/integer_type.rs index 0b6fdf6b84..01736f4647 100644 --- a/types/src/types/integer_type.rs +++ b/types/src/types/integer_type.rs @@ -11,6 +11,12 @@ pub enum IntegerType { U32, U64, U128, + + I8, + I16, + I32, + I64, + I128, } impl From for IntegerType { @@ -21,6 +27,12 @@ impl From for IntegerType { AstIntegerType::U32Type(_type) => IntegerType::U32, AstIntegerType::U64Type(_type) => IntegerType::U64, AstIntegerType::U128Type(_type) => IntegerType::U128, + + AstIntegerType::I8Type(_type) => IntegerType::I8, + AstIntegerType::I16Type(_type) => IntegerType::I16, + AstIntegerType::I32Type(_type) => IntegerType::I32, + AstIntegerType::I64Type(_type) => IntegerType::I64, + AstIntegerType::I128Type(_type) => IntegerType::I128, } } } @@ -33,6 +45,12 @@ impl fmt::Display for IntegerType { IntegerType::U32 => write!(f, "u32"), IntegerType::U64 => write!(f, "u64"), IntegerType::U128 => write!(f, "u128"), + + IntegerType::I8 => write!(f, "i8"), + IntegerType::I16 => write!(f, "i16"), + IntegerType::I32 => write!(f, "i32"), + IntegerType::I64 => write!(f, "i64"), + IntegerType::I128 => write!(f, "i128"), } } }