mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-09-21 10:49:59 +03:00
Merge pull request #112 from AleoHQ/feature/signed-integer-syntax
Feature/signed integer syntax
This commit is contained in:
commit
45e57cc0e2
27
Cargo.lock
generated
27
Cargo.lock
generated
@ -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"
|
||||
|
@ -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 }
|
||||
|
@ -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 }
|
||||
|
@ -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 {}
|
||||
|
@ -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" }
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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<F: Field + PrimeField, G: GroupType<F>, 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);
|
||||
|
@ -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<F: Field + PrimeField, G: GroupType<F>, 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);
|
||||
|
@ -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<F: Field + PrimeField, G: GroupType<F>, 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);
|
||||
|
@ -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<F: Field + PrimeField, G: GroupType<F>, 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);
|
||||
|
@ -1,28 +0,0 @@
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use snarkos_models::{
|
||||
curves::Field,
|
||||
gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean},
|
||||
};
|
||||
|
||||
pub trait EvaluateLtGadget<F: Field> {
|
||||
fn less_than<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError>;
|
||||
}
|
||||
|
||||
// implementing `EvaluateLtGadget` will implement `ComparatorGadget`
|
||||
pub trait ComparatorGadget<F: Field>
|
||||
where
|
||||
Self: EvaluateLtGadget<F>,
|
||||
{
|
||||
fn greater_than<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
|
||||
other.less_than(cs, self)
|
||||
}
|
||||
|
||||
fn less_than_or_equal<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
|
||||
let is_gt = self.greater_than(cs, other)?;
|
||||
Ok(is_gt.not())
|
||||
}
|
||||
|
||||
fn greater_than_or_equal<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
|
||||
other.less_than_or_equal(cs, self)
|
||||
}
|
||||
}
|
@ -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<F: Field + PrimeField> EvaluateEqGadget<F> for FieldType<F> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> EvaluateLtGadget<F> for FieldType<F> {
|
||||
fn less_than<CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
|
||||
match (self, other) {
|
||||
(FieldType::Constant(first), FieldType::Constant(second)) => Ok(Boolean::constant(first.lt(second))),
|
||||
(FieldType::Allocated(allocated), FieldType::Constant(constant))
|
||||
| (FieldType::Constant(constant), FieldType::Allocated(allocated)) => {
|
||||
let bool_option = allocated.value.map(|f| f.lt(constant));
|
||||
|
||||
Boolean::alloc(&mut cs.ns(|| "less than"), || {
|
||||
bool_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
}
|
||||
(FieldType::Allocated(first), FieldType::Allocated(second)) => {
|
||||
let bool_option = first.value.and_then(|a| second.value.map(|b| a.lt(&b)));
|
||||
|
||||
Boolean::alloc(&mut cs.ns(|| "less than"), || {
|
||||
bool_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> ComparatorGadget<F> for FieldType<F> {}
|
||||
|
||||
impl<F: Field + PrimeField> EqGadget<F> for FieldType<F> {}
|
||||
|
||||
impl<F: Field + PrimeField> ConditionalEqGadget<F> for FieldType<F> {
|
||||
|
@ -1,565 +0,0 @@
|
||||
//! Conversion of integer declarations to constraints in Leo.
|
||||
use crate::{
|
||||
comparator::{ComparatorGadget, EvaluateLtGadget},
|
||||
errors::IntegerError,
|
||||
};
|
||||
use leo_types::{InputValue, IntegerType, Span};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{
|
||||
r1cs::ConstraintSystem,
|
||||
utilities::{
|
||||
alloc::AllocGadget,
|
||||
boolean::Boolean,
|
||||
eq::{ConditionalEqGadget, EqGadget, EvaluateEqGadget},
|
||||
select::CondSelectGadget,
|
||||
uint::{UInt, UInt128, UInt16, UInt32, UInt64, UInt8},
|
||||
},
|
||||
},
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
/// An integer type enum wrapping the integer value.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
|
||||
pub enum Integer {
|
||||
U8(UInt8),
|
||||
U16(UInt16),
|
||||
U32(UInt32),
|
||||
U64(UInt64),
|
||||
U128(UInt128),
|
||||
}
|
||||
|
||||
impl Integer {
|
||||
pub fn from_implicit(number: String) -> Self {
|
||||
Integer::U128(UInt128::constant(number.parse::<u128>().expect("unable to parse u128")))
|
||||
}
|
||||
|
||||
pub fn new_constant(integer_type: &IntegerType, string: String, span: Span) -> Result<Self, IntegerError> {
|
||||
match integer_type {
|
||||
IntegerType::U8 => {
|
||||
let number = string
|
||||
.parse::<u8>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::U8(UInt8::constant(number)))
|
||||
}
|
||||
IntegerType::U16 => {
|
||||
let number = string
|
||||
.parse::<u16>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::U16(UInt16::constant(number)))
|
||||
}
|
||||
IntegerType::U32 => {
|
||||
let number = string
|
||||
.parse::<u32>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::U32(UInt32::constant(number)))
|
||||
}
|
||||
IntegerType::U64 => {
|
||||
let number = string
|
||||
.parse::<u64>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::U64(UInt64::constant(number)))
|
||||
}
|
||||
IntegerType::U128 => {
|
||||
let number = string
|
||||
.parse::<u128>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::U128(UInt128::constant(number)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> Option<u128> {
|
||||
match self {
|
||||
Integer::U8(u8) => u8.value.map(|v| v as u128),
|
||||
Integer::U16(u16) => u16.value.map(|v| v as u128),
|
||||
Integer::U32(u32) => u32.value.map(|v| v as u128),
|
||||
Integer::U64(u64) => u64.value.map(|v| v as u128),
|
||||
Integer::U128(u128) => u128.value.map(|v| v as u128),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_usize(&self, span: Span) -> Result<usize, IntegerError> {
|
||||
let value = self.get_value().ok_or(IntegerError::invalid_index(span))?;
|
||||
Ok(value as usize)
|
||||
}
|
||||
|
||||
pub fn to_bits_le(&self) -> Vec<Boolean> {
|
||||
match self {
|
||||
Integer::U8(num) => num.bits.clone(),
|
||||
Integer::U16(num) => num.bits.clone(),
|
||||
Integer::U32(num) => num.bits.clone(),
|
||||
Integer::U64(num) => num.bits.clone(),
|
||||
Integer::U128(num) => num.bits.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_type(&self) -> IntegerType {
|
||||
match self {
|
||||
Integer::U8(_u8) => IntegerType::U8,
|
||||
Integer::U16(_u16) => IntegerType::U16,
|
||||
Integer::U32(_u32) => IntegerType::U32,
|
||||
Integer::U64(_u64) => IntegerType::U64,
|
||||
Integer::U128(_u128) => IntegerType::U128,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocate_type<F: Field, CS: ConstraintSystem<F>>(
|
||||
cs: &mut CS,
|
||||
integer_type: IntegerType,
|
||||
name: String,
|
||||
option: Option<u128>,
|
||||
span: Span,
|
||||
) -> Result<Self, IntegerError> {
|
||||
Ok(match integer_type {
|
||||
IntegerType::U8 => {
|
||||
let u8_name = format!("{}: u8", name);
|
||||
let u8_name_unique = format!("`{}` {}:{}", u8_name, span.line, span.start);
|
||||
let u8_option = option.map(|integer| integer as u8);
|
||||
let u8_result = UInt8::alloc(cs.ns(|| u8_name_unique), || {
|
||||
u8_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(u8_name, span))?;
|
||||
|
||||
Integer::U8(u8_result)
|
||||
}
|
||||
IntegerType::U16 => {
|
||||
let u16_name = format!("{}: u16", name);
|
||||
let u16_name_unique = format!("`{}` {}:{}", u16_name, span.line, span.start);
|
||||
let u16_option = option.map(|integer| integer as u16);
|
||||
let u16_result = UInt16::alloc(cs.ns(|| u16_name_unique), || {
|
||||
u16_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(u16_name, span))?;
|
||||
|
||||
Integer::U16(u16_result)
|
||||
}
|
||||
IntegerType::U32 => {
|
||||
let u32_name = format!("{}: u32", name);
|
||||
let u32_name_unique = format!("`{}` {}:{}", u32_name, span.line, span.start);
|
||||
let u32_option = option.map(|integer| integer as u32);
|
||||
let u32_result = UInt32::alloc(cs.ns(|| u32_name_unique), || {
|
||||
u32_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(u32_name, span))?;
|
||||
|
||||
Integer::U32(u32_result)
|
||||
}
|
||||
IntegerType::U64 => {
|
||||
let u64_name = format!("{}: u64", name);
|
||||
let u64_name_unique = format!("`{}` {}:{}", u64_name, span.line, span.start);
|
||||
let u64_option = option.map(|integer| integer as u64);
|
||||
let u64_result = UInt64::alloc(cs.ns(|| u64_name_unique), || {
|
||||
u64_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(u64_name, span))?;
|
||||
|
||||
Integer::U64(u64_result)
|
||||
}
|
||||
IntegerType::U128 => {
|
||||
let u128_name = format!("{}: u128", name);
|
||||
let u128_name_unique = format!("`{}` {}:{}", u128_name, span.line, span.start);
|
||||
let u128_option = option.map(|integer| integer as u128);
|
||||
let u128_result = UInt128::alloc(cs.ns(|| u128_name_unique), || {
|
||||
u128_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(u128_name, span))?;
|
||||
|
||||
Integer::U128(u128_result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_input<F: Field, CS: ConstraintSystem<F>>(
|
||||
cs: &mut CS,
|
||||
integer_type: IntegerType,
|
||||
name: String,
|
||||
integer_value: Option<InputValue>,
|
||||
span: Span,
|
||||
) -> Result<Self, IntegerError> {
|
||||
// Check that the input value is the correct type
|
||||
let option = match integer_value {
|
||||
Some(input) => {
|
||||
if let InputValue::Integer(_type_, number) = input {
|
||||
Some(number)
|
||||
} else {
|
||||
return Err(IntegerError::invalid_integer(input.to_string(), span));
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
Self::allocate_type(cs, integer_type, name, option, span)
|
||||
}
|
||||
|
||||
pub fn add<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
other: Self,
|
||||
span: Span,
|
||||
) -> Result<Self, IntegerError> {
|
||||
let unique_namespace = format!("enforce {} + {} {}:{}", self, other, span.line, span.start);
|
||||
|
||||
Ok(match (self, other) {
|
||||
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
|
||||
let result = UInt8::addmany(cs.ns(|| unique_namespace), &[left_u8, right_u8])
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
|
||||
|
||||
Integer::U8(result)
|
||||
}
|
||||
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
|
||||
let result = UInt16::addmany(cs.ns(|| unique_namespace), &[left_u16, right_u16])
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
|
||||
|
||||
Integer::U16(result)
|
||||
}
|
||||
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
|
||||
let result = UInt32::addmany(cs.ns(|| unique_namespace), &[left_u32, right_u32])
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
|
||||
|
||||
Integer::U32(result)
|
||||
}
|
||||
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
|
||||
let result = UInt64::addmany(cs.ns(|| unique_namespace), &[left_u64, right_u64])
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
|
||||
|
||||
Integer::U64(result)
|
||||
}
|
||||
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
|
||||
let result = UInt128::addmany(cs.ns(|| unique_namespace), &[left_u128, right_u128])
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("+"), e, span))?;
|
||||
|
||||
Integer::U128(result)
|
||||
}
|
||||
(_, _) => return Err(IntegerError::cannot_evaluate(format!("+"), span)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn sub<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
other: Self,
|
||||
span: Span,
|
||||
) -> Result<Self, IntegerError> {
|
||||
let unique_namespace = format!("enforce {} - {} {}:{}", self, other, span.line, span.start);
|
||||
|
||||
Ok(match (self, other) {
|
||||
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
|
||||
let result = left_u8
|
||||
.sub(cs.ns(|| unique_namespace), &right_u8)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
|
||||
|
||||
Integer::U8(result)
|
||||
}
|
||||
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
|
||||
let result = left_u16
|
||||
.sub(cs.ns(|| unique_namespace), &right_u16)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
|
||||
|
||||
Integer::U16(result)
|
||||
}
|
||||
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
|
||||
let result = left_u32
|
||||
.sub(cs.ns(|| unique_namespace), &right_u32)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
|
||||
|
||||
Integer::U32(result)
|
||||
}
|
||||
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
|
||||
let result = left_u64
|
||||
.sub(cs.ns(|| unique_namespace), &right_u64)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
|
||||
|
||||
Integer::U64(result)
|
||||
}
|
||||
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
|
||||
let result = left_u128
|
||||
.sub(cs.ns(|| unique_namespace), &right_u128)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("-"), e, span))?;
|
||||
|
||||
Integer::U128(result)
|
||||
}
|
||||
(_, _) => return Err(IntegerError::cannot_evaluate(format!("-"), span)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn mul<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
other: Self,
|
||||
span: Span,
|
||||
) -> Result<Self, IntegerError> {
|
||||
let unique_namespace = format!("enforce {} * {} {}:{}", self, other, span.line, span.start);
|
||||
|
||||
Ok(match (self, other) {
|
||||
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
|
||||
let result = left_u8
|
||||
.mul(cs.ns(|| unique_namespace), &right_u8)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
|
||||
|
||||
Integer::U8(result)
|
||||
}
|
||||
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
|
||||
let result = left_u16
|
||||
.mul(cs.ns(|| unique_namespace), &right_u16)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
|
||||
|
||||
Integer::U16(result)
|
||||
}
|
||||
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
|
||||
let result = left_u32
|
||||
.mul(cs.ns(|| unique_namespace), &right_u32)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
|
||||
|
||||
Integer::U32(result)
|
||||
}
|
||||
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
|
||||
let result = left_u64
|
||||
.mul(cs.ns(|| unique_namespace), &right_u64)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
|
||||
|
||||
Integer::U64(result)
|
||||
}
|
||||
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
|
||||
let result = left_u128
|
||||
.mul(cs.ns(|| unique_namespace), &right_u128)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("*"), e, span))?;
|
||||
|
||||
Integer::U128(result)
|
||||
}
|
||||
(_, _) => return Err(IntegerError::cannot_evaluate(format!("*"), span)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn div<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
other: Self,
|
||||
span: Span,
|
||||
) -> Result<Self, IntegerError> {
|
||||
let unique_namespace = format!("enforce {} ÷ {} {}:{}", self, other, span.line, span.start);
|
||||
|
||||
Ok(match (self, other) {
|
||||
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
|
||||
let result = left_u8
|
||||
.div(cs.ns(|| unique_namespace), &right_u8)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
|
||||
|
||||
Integer::U8(result)
|
||||
}
|
||||
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
|
||||
let result = left_u16
|
||||
.div(cs.ns(|| unique_namespace), &right_u16)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
|
||||
|
||||
Integer::U16(result)
|
||||
}
|
||||
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
|
||||
let result = left_u32
|
||||
.div(cs.ns(|| unique_namespace), &right_u32)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
|
||||
|
||||
Integer::U32(result)
|
||||
}
|
||||
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
|
||||
let result = left_u64
|
||||
.div(cs.ns(|| unique_namespace), &right_u64)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
|
||||
|
||||
Integer::U64(result)
|
||||
}
|
||||
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
|
||||
let result = left_u128
|
||||
.div(cs.ns(|| unique_namespace), &right_u128)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("÷"), e, span))?;
|
||||
|
||||
Integer::U128(result)
|
||||
}
|
||||
(_, _) => return Err(IntegerError::cannot_evaluate(format!("÷"), span)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn pow<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
other: Self,
|
||||
span: Span,
|
||||
) -> Result<Self, IntegerError> {
|
||||
let unique_namespace = format!("enforce {} ** {} {}:{}", self, other, span.line, span.start);
|
||||
|
||||
Ok(match (self, other) {
|
||||
(Integer::U8(left_u8), Integer::U8(right_u8)) => {
|
||||
let result = left_u8
|
||||
.pow(cs.ns(|| unique_namespace), &right_u8)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
|
||||
|
||||
Integer::U8(result)
|
||||
}
|
||||
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
|
||||
let result = left_u16
|
||||
.pow(cs.ns(|| unique_namespace), &right_u16)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
|
||||
|
||||
Integer::U16(result)
|
||||
}
|
||||
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
|
||||
let result = left_u32
|
||||
.pow(cs.ns(|| unique_namespace), &right_u32)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
|
||||
|
||||
Integer::U32(result)
|
||||
}
|
||||
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
|
||||
let result = left_u64
|
||||
.pow(cs.ns(|| unique_namespace), &right_u64)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
|
||||
|
||||
Integer::U64(result)
|
||||
}
|
||||
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
|
||||
let result = left_u128
|
||||
.pow(cs.ns(|| unique_namespace), &right_u128)
|
||||
.map_err(|e| IntegerError::cannot_enforce(format!("**"), e, span))?;
|
||||
|
||||
Integer::U128(result)
|
||||
}
|
||||
(_, _) => return Err(IntegerError::cannot_evaluate(format!("**"), span)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> EvaluateEqGadget<F> for Integer {
|
||||
fn evaluate_equal<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
|
||||
match (self, other) {
|
||||
(Integer::U8(left_u8), Integer::U8(right_u8)) => left_u8.evaluate_equal(cs, right_u8),
|
||||
(Integer::U16(left_u16), Integer::U16(right_u16)) => left_u16.evaluate_equal(cs, right_u16),
|
||||
(Integer::U32(left_u32), Integer::U32(right_u32)) => left_u32.evaluate_equal(cs, right_u32),
|
||||
(Integer::U64(left_u64), Integer::U64(right_u64)) => left_u64.evaluate_equal(cs, right_u64),
|
||||
(Integer::U128(left_u128), Integer::U128(right_u128)) => left_u128.evaluate_equal(cs, right_u128),
|
||||
(_, _) => Err(SynthesisError::AssignmentMissing),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> EvaluateLtGadget<F> for Integer {
|
||||
fn less_than<CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
|
||||
if self.to_bits_le().len() != other.to_bits_le().len() {
|
||||
return Err(SynthesisError::Unsatisfiable);
|
||||
}
|
||||
|
||||
for (i, (self_bit, other_bit)) in self
|
||||
.to_bits_le()
|
||||
.iter()
|
||||
.rev()
|
||||
.zip(other.to_bits_le().iter().rev())
|
||||
.enumerate()
|
||||
{
|
||||
// is_greater = a & !b
|
||||
// only true when a > b
|
||||
let is_greater = Boolean::and(cs.ns(|| format!("a and not b [{}]", i)), self_bit, &other_bit.not())?;
|
||||
|
||||
// is_less = !a & b
|
||||
// only true when a < b
|
||||
let is_less = Boolean::and(cs.ns(|| format!("not a and b [{}]", i)), &self_bit.not(), other_bit)?;
|
||||
|
||||
if is_greater.get_value().unwrap() {
|
||||
return Ok(is_greater.not());
|
||||
} else if is_less.get_value().unwrap() {
|
||||
return Ok(is_less);
|
||||
} else if i == self.to_bits_le().len() - 1 {
|
||||
return Ok(is_less);
|
||||
}
|
||||
}
|
||||
|
||||
Err(SynthesisError::Unsatisfiable)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> ComparatorGadget<F> for Integer {}
|
||||
|
||||
impl<F: Field + PrimeField> EqGadget<F> for Integer {}
|
||||
|
||||
impl<F: Field + PrimeField> ConditionalEqGadget<F> for Integer {
|
||||
fn conditional_enforce_equal<CS: ConstraintSystem<F>>(
|
||||
&self,
|
||||
cs: CS,
|
||||
other: &Self,
|
||||
condition: &Boolean,
|
||||
) -> Result<(), SynthesisError> {
|
||||
match (self, other) {
|
||||
(Integer::U8(left_u8), Integer::U8(right_u8)) => left_u8.conditional_enforce_equal(cs, right_u8, condition),
|
||||
(Integer::U16(left_u16), Integer::U16(right_u16)) => {
|
||||
left_u16.conditional_enforce_equal(cs, right_u16, condition)
|
||||
}
|
||||
(Integer::U32(left_u32), Integer::U32(right_u32)) => {
|
||||
left_u32.conditional_enforce_equal(cs, right_u32, condition)
|
||||
}
|
||||
(Integer::U64(left_u64), Integer::U64(right_u64)) => {
|
||||
left_u64.conditional_enforce_equal(cs, right_u64, condition)
|
||||
}
|
||||
(Integer::U128(left_u128), Integer::U128(right_u128)) => {
|
||||
left_u128.conditional_enforce_equal(cs, right_u128, condition)
|
||||
}
|
||||
(_, _) => Err(SynthesisError::AssignmentMissing),
|
||||
}
|
||||
}
|
||||
|
||||
fn cost() -> usize {
|
||||
<UInt128 as ConditionalEqGadget<F>>::cost()
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> CondSelectGadget<F> for Integer {
|
||||
fn conditionally_select<CS: ConstraintSystem<F>>(
|
||||
cs: CS,
|
||||
cond: &Boolean,
|
||||
first: &Self,
|
||||
second: &Self,
|
||||
) -> Result<Self, SynthesisError> {
|
||||
match (first, second) {
|
||||
(Integer::U8(u8_first), Integer::U8(u8_second)) => {
|
||||
Ok(Integer::U8(UInt8::conditionally_select(cs, cond, u8_first, u8_second)?))
|
||||
}
|
||||
(Integer::U16(u16_first), Integer::U16(u18_second)) => Ok(Integer::U16(UInt16::conditionally_select(
|
||||
cs, cond, u16_first, u18_second,
|
||||
)?)),
|
||||
(Integer::U32(u32_first), Integer::U32(u32_second)) => Ok(Integer::U32(UInt32::conditionally_select(
|
||||
cs, cond, u32_first, u32_second,
|
||||
)?)),
|
||||
(Integer::U64(u64_first), Integer::U64(u64_second)) => Ok(Integer::U64(UInt64::conditionally_select(
|
||||
cs, cond, u64_first, u64_second,
|
||||
)?)),
|
||||
(Integer::U128(u128_first), Integer::U128(u128_second)) => Ok(Integer::U128(
|
||||
UInt128::conditionally_select(cs, cond, u128_first, u128_second)?,
|
||||
)),
|
||||
(_, _) => Err(SynthesisError::Unsatisfiable), // types do not match
|
||||
}
|
||||
}
|
||||
|
||||
fn cost() -> usize {
|
||||
unimplemented!("Cannot calculate cost.")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Integer {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let option = match self {
|
||||
Integer::U8(u8) => u8.value.map(|num| num as u128),
|
||||
Integer::U16(u16) => u16.value.map(|num| num as u128),
|
||||
Integer::U32(u32) => u32.value.map(|num| num as u128),
|
||||
Integer::U64(u64) => u64.value.map(|num| num as u128),
|
||||
Integer::U128(u128) => u128.value.map(|num| num as u128),
|
||||
};
|
||||
match option {
|
||||
Some(number) => write!(f, "{}{}", number, self.get_type()),
|
||||
None => write!(f, "[input]{}", self.get_type()),
|
||||
}
|
||||
}
|
||||
}
|
507
compiler/src/value/integer/integer.rs
Normal file
507
compiler/src/value/integer/integer.rs
Normal file
@ -0,0 +1,507 @@
|
||||
//! Conversion of integer declarations to constraints in Leo.
|
||||
use crate::{errors::IntegerError, integer::macros::IntegerTrait};
|
||||
use leo_gadgets::{
|
||||
arithmetic::*,
|
||||
bits::comparator::{ComparatorGadget, EvaluateLtGadget},
|
||||
signed_integer::*,
|
||||
};
|
||||
use leo_types::{InputValue, IntegerType, Span};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{
|
||||
r1cs::ConstraintSystem,
|
||||
utilities::{
|
||||
alloc::AllocGadget,
|
||||
boolean::Boolean,
|
||||
eq::{ConditionalEqGadget, EqGadget, EvaluateEqGadget},
|
||||
select::CondSelectGadget,
|
||||
uint::{UInt, UInt128, UInt16, UInt32, UInt64, UInt8},
|
||||
},
|
||||
},
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
/// An integer type enum wrapping the integer value.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
|
||||
pub enum Integer {
|
||||
U8(UInt8),
|
||||
U16(UInt16),
|
||||
U32(UInt32),
|
||||
U64(UInt64),
|
||||
U128(UInt128),
|
||||
|
||||
I8(Int8),
|
||||
I16(Int16),
|
||||
I32(Int32),
|
||||
I64(Int64),
|
||||
I128(Int128),
|
||||
}
|
||||
|
||||
impl fmt::Display for Integer {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let integer = self;
|
||||
let option = match_integer!(integer => integer.get_value());
|
||||
match option {
|
||||
Some(number) => write!(f, "{}{}", number, self.get_type()),
|
||||
None => write!(f, "[input]{}", self.get_type()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Integer {
|
||||
pub fn new_constant(integer_type: &IntegerType, string: String, span: Span) -> Result<Self, IntegerError> {
|
||||
match integer_type {
|
||||
IntegerType::U8 => {
|
||||
let number = string
|
||||
.parse::<u8>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::U8(UInt8::constant(number)))
|
||||
}
|
||||
IntegerType::U16 => {
|
||||
let number = string
|
||||
.parse::<u16>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::U16(UInt16::constant(number)))
|
||||
}
|
||||
IntegerType::U32 => {
|
||||
let number = string
|
||||
.parse::<u32>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::U32(UInt32::constant(number)))
|
||||
}
|
||||
IntegerType::U64 => {
|
||||
let number = string
|
||||
.parse::<u64>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::U64(UInt64::constant(number)))
|
||||
}
|
||||
IntegerType::U128 => {
|
||||
let number = string
|
||||
.parse::<u128>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::U128(UInt128::constant(number)))
|
||||
}
|
||||
|
||||
IntegerType::I8 => {
|
||||
let number = string
|
||||
.parse::<i8>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::I8(Int8::constant(number)))
|
||||
}
|
||||
IntegerType::I16 => {
|
||||
let number = string
|
||||
.parse::<i16>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::I16(Int16::constant(number)))
|
||||
}
|
||||
IntegerType::I32 => {
|
||||
let number = string
|
||||
.parse::<i32>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::I32(Int32::constant(number)))
|
||||
}
|
||||
IntegerType::I64 => {
|
||||
let number = string
|
||||
.parse::<i64>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::I64(Int64::constant(number)))
|
||||
}
|
||||
IntegerType::I128 => {
|
||||
let number = string
|
||||
.parse::<i128>()
|
||||
.map_err(|_| IntegerError::invalid_integer(string, span))?;
|
||||
|
||||
Ok(Integer::I128(Int128::constant(number)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_bits(&self) -> Vec<Boolean> {
|
||||
let integer = self;
|
||||
match_integer!(integer => integer.get_bits())
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> Option<String> {
|
||||
let integer = self;
|
||||
match_integer!(integer => integer.get_value())
|
||||
}
|
||||
|
||||
pub fn to_usize(&self, span: Span) -> Result<usize, IntegerError> {
|
||||
let value = self.get_value().ok_or(IntegerError::invalid_index(span.clone()))?;
|
||||
let value_usize = value
|
||||
.parse::<usize>()
|
||||
.map_err(|_| IntegerError::invalid_integer(value, span))?;
|
||||
Ok(value_usize)
|
||||
}
|
||||
|
||||
pub fn get_type(&self) -> IntegerType {
|
||||
match self {
|
||||
Integer::U8(_u8) => IntegerType::U8,
|
||||
Integer::U16(_u16) => IntegerType::U16,
|
||||
Integer::U32(_u32) => IntegerType::U32,
|
||||
Integer::U64(_u64) => IntegerType::U64,
|
||||
Integer::U128(_u128) => IntegerType::U128,
|
||||
|
||||
Integer::I8(_u8) => IntegerType::I8,
|
||||
Integer::I16(_u16) => IntegerType::I16,
|
||||
Integer::I32(_u32) => IntegerType::I32,
|
||||
Integer::I64(_u64) => IntegerType::I64,
|
||||
Integer::I128(_u128) => IntegerType::I128,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocate_type<F: Field, CS: ConstraintSystem<F>>(
|
||||
cs: &mut CS,
|
||||
integer_type: IntegerType,
|
||||
name: String,
|
||||
option: Option<String>,
|
||||
span: Span,
|
||||
) -> Result<Self, IntegerError> {
|
||||
Ok(match integer_type {
|
||||
IntegerType::U8 => {
|
||||
let u8_name = format!("{}: u8", name);
|
||||
let u8_name_unique = format!("`{}` {}:{}", u8_name, span.line, span.start);
|
||||
|
||||
let u8_option = option.map(|s| {
|
||||
s.parse::<u8>()
|
||||
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
let u8_result = UInt8::alloc(cs.ns(|| u8_name_unique), || {
|
||||
u8_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(u8_name, span))?;
|
||||
|
||||
Integer::U8(u8_result)
|
||||
}
|
||||
IntegerType::U16 => {
|
||||
let u16_name = format!("{}: u16", name);
|
||||
let u16_name_unique = format!("`{}` {}:{}", u16_name, span.line, span.start);
|
||||
let u16_option = option.map(|s| {
|
||||
s.parse::<u16>()
|
||||
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
|
||||
.unwrap()
|
||||
});
|
||||
let u16_result = UInt16::alloc(cs.ns(|| u16_name_unique), || {
|
||||
u16_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(u16_name, span))?;
|
||||
|
||||
Integer::U16(u16_result)
|
||||
}
|
||||
IntegerType::U32 => {
|
||||
let u32_name = format!("{}: u32", name);
|
||||
let u32_name_unique = format!("`{}` {}:{}", u32_name, span.line, span.start);
|
||||
let u32_option = option.map(|s| {
|
||||
s.parse::<u32>()
|
||||
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
|
||||
.unwrap()
|
||||
});
|
||||
let u32_result = UInt32::alloc(cs.ns(|| u32_name_unique), || {
|
||||
u32_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(u32_name, span))?;
|
||||
|
||||
Integer::U32(u32_result)
|
||||
}
|
||||
IntegerType::U64 => {
|
||||
let u64_name = format!("{}: u64", name);
|
||||
let u64_name_unique = format!("`{}` {}:{}", u64_name, span.line, span.start);
|
||||
let u64_option = option.map(|s| {
|
||||
s.parse::<u64>()
|
||||
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
|
||||
.unwrap()
|
||||
});
|
||||
let u64_result = UInt64::alloc(cs.ns(|| u64_name_unique), || {
|
||||
u64_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(u64_name, span))?;
|
||||
|
||||
Integer::U64(u64_result)
|
||||
}
|
||||
IntegerType::U128 => {
|
||||
let u128_name = format!("{}: u128", name);
|
||||
let u128_name_unique = format!("`{}` {}:{}", u128_name, span.line, span.start);
|
||||
let u128_option = option.map(|s| {
|
||||
s.parse::<u128>()
|
||||
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
|
||||
.unwrap()
|
||||
});
|
||||
let u128_result = UInt128::alloc(cs.ns(|| u128_name_unique), || {
|
||||
u128_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(u128_name, span))?;
|
||||
|
||||
Integer::U128(u128_result)
|
||||
}
|
||||
|
||||
IntegerType::I8 => {
|
||||
let i8_name = format!("{}: i8", name);
|
||||
let i8_name_unique = format!("`{}` {}:{}", i8_name, span.line, span.start);
|
||||
let i8_option = option.map(|s| {
|
||||
s.parse::<i8>()
|
||||
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
|
||||
.unwrap()
|
||||
});
|
||||
let i8_result = Int8::alloc(cs.ns(|| i8_name_unique), || {
|
||||
i8_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(i8_name, span))?;
|
||||
|
||||
Integer::I8(i8_result)
|
||||
}
|
||||
IntegerType::I16 => {
|
||||
let i16_name = format!("{}: i16", name);
|
||||
let i16_name_unique = format!("`{}` {}:{}", i16_name, span.line, span.start);
|
||||
let i16_option = option.map(|s| {
|
||||
s.parse::<i16>()
|
||||
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
|
||||
.unwrap()
|
||||
});
|
||||
let i16_result = Int16::alloc(cs.ns(|| i16_name_unique), || {
|
||||
i16_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(i16_name, span))?;
|
||||
|
||||
Integer::I16(i16_result)
|
||||
}
|
||||
IntegerType::I32 => {
|
||||
let i32_name = format!("{}: i32", name);
|
||||
let i32_name_unique = format!("`{}` {}:{}", i32_name, span.line, span.start);
|
||||
let i32_option = option.map(|s| {
|
||||
s.parse::<i32>()
|
||||
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
|
||||
.unwrap()
|
||||
});
|
||||
let i32_result = Int32::alloc(cs.ns(|| i32_name_unique), || {
|
||||
i32_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(i32_name, span))?;
|
||||
|
||||
Integer::I32(i32_result)
|
||||
}
|
||||
IntegerType::I64 => {
|
||||
let i64_name = format!("{}: i64", name);
|
||||
let i64_name_unique = format!("`{}` {}:{}", i64_name, span.line, span.start);
|
||||
let i64_option = option.map(|s| {
|
||||
s.parse::<i64>()
|
||||
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
|
||||
.unwrap()
|
||||
});
|
||||
let i64_result = Int64::alloc(cs.ns(|| i64_name_unique), || {
|
||||
i64_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(i64_name, span))?;
|
||||
|
||||
Integer::I64(i64_result)
|
||||
}
|
||||
IntegerType::I128 => {
|
||||
let i128_name = format!("{}: i128", name);
|
||||
let i128_name_unique = format!("`{}` {}:{}", i128_name, span.line, span.start);
|
||||
let i128_option = option.map(|s| {
|
||||
s.parse::<i128>()
|
||||
.map_err(|_| IntegerError::invalid_integer(s, span.clone()))
|
||||
.unwrap()
|
||||
});
|
||||
let i128_result = Int128::alloc(cs.ns(|| i128_name_unique), || {
|
||||
i128_option.ok_or(SynthesisError::AssignmentMissing)
|
||||
})
|
||||
.map_err(|_| IntegerError::missing_integer(i128_name, span))?;
|
||||
|
||||
Integer::I128(i128_result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_input<F: Field, CS: ConstraintSystem<F>>(
|
||||
cs: &mut CS,
|
||||
integer_type: IntegerType,
|
||||
name: String,
|
||||
integer_value: Option<InputValue>,
|
||||
span: Span,
|
||||
) -> Result<Self, IntegerError> {
|
||||
// Check that the input value is the correct type
|
||||
let option = match integer_value {
|
||||
Some(input) => {
|
||||
if let InputValue::Integer(_type_, number) = input {
|
||||
Some(number)
|
||||
} else {
|
||||
return Err(IntegerError::invalid_integer(input.to_string(), span));
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
Self::allocate_type(cs, integer_type, name, option, span)
|
||||
}
|
||||
|
||||
pub fn add<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
other: Self,
|
||||
span: Span,
|
||||
) -> Result<Self, IntegerError> {
|
||||
let unique_namespace = format!("enforce {} + {} {}:{}", self, other, span.line, span.start);
|
||||
|
||||
let a = self;
|
||||
let b = other;
|
||||
let s = span.clone();
|
||||
|
||||
let result = match_integers_span!((a, b), s => a.add(cs.ns(|| unique_namespace), &b));
|
||||
|
||||
result.ok_or(IntegerError::cannot_evaluate(format!("+"), span))
|
||||
}
|
||||
|
||||
pub fn sub<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
other: Self,
|
||||
span: Span,
|
||||
) -> Result<Self, IntegerError> {
|
||||
let unique_namespace = format!("enforce {} - {} {}:{}", self, other, span.line, span.start);
|
||||
|
||||
let a = self;
|
||||
let b = other;
|
||||
let s = span.clone();
|
||||
|
||||
let result = match_integers_span!((a, b), s => a.sub(cs.ns(|| unique_namespace), &b));
|
||||
|
||||
result.ok_or(IntegerError::cannot_evaluate(format!("-"), span))
|
||||
}
|
||||
|
||||
pub fn mul<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
other: Self,
|
||||
span: Span,
|
||||
) -> Result<Self, IntegerError> {
|
||||
let unique_namespace = format!("enforce {} * {} {}:{}", self, other, span.line, span.start);
|
||||
|
||||
let a = self;
|
||||
let b = other;
|
||||
let s = span.clone();
|
||||
|
||||
let result = match_integers_span!((a, b), s => a.mul(cs.ns(|| unique_namespace), &b));
|
||||
|
||||
result.ok_or(IntegerError::cannot_evaluate(format!("*"), span))
|
||||
}
|
||||
|
||||
pub fn div<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
other: Self,
|
||||
span: Span,
|
||||
) -> Result<Self, IntegerError> {
|
||||
let unique_namespace = format!("enforce {} ÷ {} {}:{}", self, other, span.line, span.start);
|
||||
|
||||
let a = self;
|
||||
let b = other;
|
||||
let s = span.clone();
|
||||
|
||||
let result = match_integers_span!((a, b), s => a.div(cs.ns(|| unique_namespace), &b));
|
||||
|
||||
result.ok_or(IntegerError::cannot_evaluate(format!("÷"), span))
|
||||
}
|
||||
|
||||
pub fn pow<F: Field + PrimeField, CS: ConstraintSystem<F>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
other: Self,
|
||||
span: Span,
|
||||
) -> Result<Self, IntegerError> {
|
||||
let unique_namespace = format!("enforce {} ** {} {}:{}", self, other, span.line, span.start);
|
||||
|
||||
let a = self;
|
||||
let b = other;
|
||||
let s = span.clone();
|
||||
|
||||
let result = match_integers_span!((a, b), s => a.pow(cs.ns(|| unique_namespace), &b));
|
||||
|
||||
result.ok_or(IntegerError::cannot_evaluate(format!("**"), span))
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> EvaluateEqGadget<F> for Integer {
|
||||
fn evaluate_equal<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
|
||||
let a = self;
|
||||
let b = other;
|
||||
|
||||
let result = match_integers!((a, b) => a.evaluate_equal(cs, b));
|
||||
|
||||
result.ok_or(SynthesisError::Unsatisfiable)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> EvaluateLtGadget<F> for Integer {
|
||||
fn less_than<CS: ConstraintSystem<F>>(&self, cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
|
||||
let a = self;
|
||||
let b = other;
|
||||
let result = match_integers!((a, b) => a.less_than(cs, b));
|
||||
|
||||
result.ok_or(SynthesisError::Unsatisfiable)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> ComparatorGadget<F> for Integer {}
|
||||
|
||||
impl<F: Field + PrimeField> EqGadget<F> for Integer {}
|
||||
|
||||
impl<F: Field + PrimeField> ConditionalEqGadget<F> for Integer {
|
||||
fn conditional_enforce_equal<CS: ConstraintSystem<F>>(
|
||||
&self,
|
||||
cs: CS,
|
||||
other: &Self,
|
||||
condition: &Boolean,
|
||||
) -> Result<(), SynthesisError> {
|
||||
let a = self;
|
||||
let b = other;
|
||||
|
||||
let result = match_integers!((a, b) => a.conditional_enforce_equal(cs, b, condition));
|
||||
|
||||
result.ok_or(SynthesisError::Unsatisfiable)
|
||||
}
|
||||
|
||||
fn cost() -> usize {
|
||||
<UInt128 as ConditionalEqGadget<F>>::cost() // upper bound. change trait to increase accuracy
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField> CondSelectGadget<F> for Integer {
|
||||
fn conditionally_select<CS: ConstraintSystem<F>>(
|
||||
cs: CS,
|
||||
cond: &Boolean,
|
||||
first: &Self,
|
||||
second: &Self,
|
||||
) -> Result<Self, SynthesisError> {
|
||||
match (first, second) {
|
||||
(Integer::U8(a), Integer::U8(b)) => Ok(Integer::U8(UInt8::conditionally_select(cs, cond, a, b)?)),
|
||||
(Integer::U16(a), Integer::U16(b)) => Ok(Integer::U16(UInt16::conditionally_select(cs, cond, a, b)?)),
|
||||
(Integer::U32(a), Integer::U32(b)) => Ok(Integer::U32(UInt32::conditionally_select(cs, cond, a, b)?)),
|
||||
(Integer::U64(a), Integer::U64(b)) => Ok(Integer::U64(UInt64::conditionally_select(cs, cond, a, b)?)),
|
||||
(Integer::U128(a), Integer::U128(b)) => Ok(Integer::U128(UInt128::conditionally_select(cs, cond, a, b)?)),
|
||||
(Integer::I8(a), Integer::I8(b)) => Ok(Integer::I8(Int8::conditionally_select(cs, cond, a, b)?)),
|
||||
(Integer::I16(a), Integer::I16(b)) => Ok(Integer::I16(Int16::conditionally_select(cs, cond, a, b)?)),
|
||||
(Integer::I32(a), Integer::I32(b)) => Ok(Integer::I32(Int32::conditionally_select(cs, cond, a, b)?)),
|
||||
(Integer::I64(a), Integer::I64(b)) => Ok(Integer::I64(Int64::conditionally_select(cs, cond, a, b)?)),
|
||||
(Integer::I128(a), Integer::I128(b)) => Ok(Integer::I128(Int128::conditionally_select(cs, cond, a, b)?)),
|
||||
|
||||
(_, _) => Err(SynthesisError::Unsatisfiable), // types do not match
|
||||
}
|
||||
}
|
||||
|
||||
fn cost() -> usize {
|
||||
<UInt128 as CondSelectGadget<F>>::cost() // upper bound. change trait to increase accuracy
|
||||
}
|
||||
}
|
110
compiler/src/value/integer/macros.rs
Normal file
110
compiler/src/value/integer/macros.rs
Normal file
@ -0,0 +1,110 @@
|
||||
use leo_gadgets::signed_integer::*;
|
||||
|
||||
use snarkos_models::gadgets::utilities::{
|
||||
boolean::Boolean,
|
||||
uint::{UInt128, UInt16, UInt32, UInt64, UInt8},
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub trait IntegerTrait: Sized + Clone + Debug {
|
||||
fn get_value(&self) -> Option<String>;
|
||||
|
||||
fn get_bits(&self) -> Vec<Boolean>;
|
||||
}
|
||||
|
||||
macro_rules! integer_trait_impl {
|
||||
($($gadget: ident)*) => ($(
|
||||
impl IntegerTrait for $gadget {
|
||||
fn get_value(&self) -> Option<String> {
|
||||
self.value.map(|num| num.to_string())
|
||||
}
|
||||
|
||||
fn get_bits(&self) -> Vec<Boolean> {
|
||||
self.bits.clone()
|
||||
}
|
||||
}
|
||||
|
||||
)*)
|
||||
}
|
||||
|
||||
integer_trait_impl!(UInt8 UInt16 UInt32 UInt64 UInt128 Int8 Int16 Int32 Int64 Int128);
|
||||
|
||||
/// Useful macros to avoid duplicating `match` constructions.
|
||||
#[macro_export]
|
||||
macro_rules! match_integer {
|
||||
($integer: ident => $expression: expr) => {
|
||||
match $integer {
|
||||
Integer::U8($integer) => $expression,
|
||||
Integer::U16($integer) => $expression,
|
||||
Integer::U32($integer) => $expression,
|
||||
Integer::U64($integer) => $expression,
|
||||
Integer::U128($integer) => $expression,
|
||||
|
||||
Integer::I8($integer) => $expression,
|
||||
Integer::I16($integer) => $expression,
|
||||
Integer::I32($integer) => $expression,
|
||||
Integer::I64($integer) => $expression,
|
||||
Integer::I128($integer) => $expression,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! match_integers {
|
||||
(($a: ident, $b: ident) => $expression:expr) => {
|
||||
match ($a, $b) {
|
||||
(Integer::U8($a), Integer::U8($b)) => Some($expression?),
|
||||
(Integer::U16($a), Integer::U16($b)) => Some($expression?),
|
||||
(Integer::U32($a), Integer::U32($b)) => Some($expression?),
|
||||
(Integer::U64($a), Integer::U64($b)) => Some($expression?),
|
||||
(Integer::U128($a), Integer::U128($b)) => Some($expression?),
|
||||
|
||||
(Integer::I8($a), Integer::I8($b)) => Some($expression?),
|
||||
(Integer::I16($a), Integer::I16($b)) => Some($expression?),
|
||||
(Integer::I32($a), Integer::I32($b)) => Some($expression?),
|
||||
(Integer::I64($a), Integer::I64($b)) => Some($expression?),
|
||||
(Integer::I128($a), Integer::I128($b)) => Some($expression?),
|
||||
(_, _) => None,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! match_integers_span {
|
||||
(($a: ident, $b: ident), $span: ident => $expression:expr) => {
|
||||
match ($a, $b) {
|
||||
(Integer::U8($a), Integer::U8($b)) => {
|
||||
Some(Integer::U8($expression.map_err(|e| IntegerError::synthesis(e, $span))?))
|
||||
}
|
||||
(Integer::U16($a), Integer::U16($b)) => Some(Integer::U16(
|
||||
$expression.map_err(|e| IntegerError::synthesis(e, $span))?,
|
||||
)),
|
||||
(Integer::U32($a), Integer::U32($b)) => Some(Integer::U32(
|
||||
$expression.map_err(|e| IntegerError::synthesis(e, $span))?,
|
||||
)),
|
||||
(Integer::U64($a), Integer::U64($b)) => Some(Integer::U64(
|
||||
$expression.map_err(|e| IntegerError::synthesis(e, $span))?,
|
||||
)),
|
||||
(Integer::U128($a), Integer::U128($b)) => Some(Integer::U128(
|
||||
$expression.map_err(|e| IntegerError::synthesis(e, $span))?,
|
||||
)),
|
||||
|
||||
(Integer::I8($a), Integer::I8($b)) => {
|
||||
Some(Integer::I8($expression.map_err(|e| IntegerError::signed(e, $span))?))
|
||||
}
|
||||
(Integer::I16($a), Integer::I16($b)) => {
|
||||
Some(Integer::I16($expression.map_err(|e| IntegerError::signed(e, $span))?))
|
||||
}
|
||||
(Integer::I32($a), Integer::I32($b)) => {
|
||||
Some(Integer::I32($expression.map_err(|e| IntegerError::signed(e, $span))?))
|
||||
}
|
||||
(Integer::I64($a), Integer::I64($b)) => {
|
||||
Some(Integer::I64($expression.map_err(|e| IntegerError::signed(e, $span))?))
|
||||
}
|
||||
(Integer::I128($a), Integer::I128($b)) => {
|
||||
Some(Integer::I128($expression.map_err(|e| IntegerError::signed(e, $span))?))
|
||||
}
|
||||
(_, _) => None,
|
||||
}
|
||||
};
|
||||
}
|
6
compiler/src/value/integer/mod.rs
Normal file
6
compiler/src/value/integer/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
#[macro_use]
|
||||
pub mod macros;
|
||||
pub use self::macros::*;
|
||||
|
||||
pub mod integer;
|
||||
pub use self::integer::*;
|
@ -5,8 +5,6 @@ pub use self::address::*;
|
||||
|
||||
pub mod boolean;
|
||||
|
||||
pub(crate) mod comparator;
|
||||
|
||||
pub mod field;
|
||||
pub use self::field::*;
|
||||
|
||||
|
@ -191,7 +191,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
||||
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)?;
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
function main() -> u32[3] {
|
||||
return [1u32; 3]
|
||||
return [1u32; 3]
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> u32[3] {
|
||||
return [1u32, 1u32, 1u32]
|
||||
return [1u32, 1u32, 1u32]
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main(arr: u32[3]) -> u32[3] {
|
||||
return arr
|
||||
return arr
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
}
|
@ -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]
|
||||
}
|
||||
|
@ -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]
|
||||
}
|
@ -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
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return false
|
||||
return false
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return false && false
|
||||
return false && false
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return false || false
|
||||
return false || false
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main(b: bool) -> bool{
|
||||
return b
|
||||
return b
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return !false
|
||||
return !false
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return !true
|
||||
return !true
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return !1u32
|
||||
return !1u32
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return true
|
||||
return true
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return true && false
|
||||
return true && false
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return true && true
|
||||
return true && true
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return true && 1u32
|
||||
return true && 1u32
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return true || false
|
||||
return true || false
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return true || true
|
||||
return true || true
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> bool {
|
||||
return true || 1u32
|
||||
return true || 1u32
|
||||
}
|
@ -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 }
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
circuit Circ {
|
||||
x: u32
|
||||
circuit Foo {
|
||||
x: u32
|
||||
}
|
||||
|
||||
function main() {
|
||||
let c = Circ { y: 0u32 };
|
||||
let c = Foo { y: 0u32 };
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() {
|
||||
let c = Circ { };
|
||||
let c = Foo { };
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
@ -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 `::`
|
||||
}
|
@ -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)
|
||||
}
|
@ -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 `.`
|
||||
}
|
@ -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)
|
||||
}
|
@ -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,
|
||||
|
@ -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()
|
||||
}
|
@ -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()
|
||||
}
|
@ -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()
|
||||
}
|
@ -5,6 +5,6 @@ circuit Foo {
|
||||
}
|
||||
|
||||
function main() -> u32 {
|
||||
let circuit = Foo { };
|
||||
return circuit.bar()
|
||||
let foo = Foo { };
|
||||
return foo.bar()
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main(a: field, b: field) -> field {
|
||||
return a + b
|
||||
return a + b
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main(a: field, b: field) {
|
||||
assert_eq!(a, b);
|
||||
assert_eq!(a, b);
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main(a: field, b: field) -> field {
|
||||
return a / b
|
||||
return a / b
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main(a: field, b: field) -> bool {
|
||||
return a == b
|
||||
return a == b
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
function main(a: field, b: field) -> bool {
|
||||
return a >= b
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
function main(a: field, b: field) -> bool {
|
||||
return a > b
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main(f: field) -> field{
|
||||
return f
|
||||
return f
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
function main(a: field, b: field) -> bool {
|
||||
return a <= b
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
function main(a: field, b: field) -> bool {
|
||||
return a < b
|
||||
}
|
@ -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::<Fq>::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::<Fq>::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::<Fq>::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::<Fq>::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::<Fq>::new();
|
||||
|
@ -1,3 +1,3 @@
|
||||
function main(a: field, b: field) -> field {
|
||||
return a * b
|
||||
return a * b
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> field {
|
||||
return 1field
|
||||
return 1field
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main(a: field, b: field) -> field {
|
||||
return a - b
|
||||
return a - b
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main(b: bool, f1: field, f2: field) -> field {
|
||||
return if b ? f1 : f2
|
||||
return if b ? f1 : f2
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> field {
|
||||
return 0field
|
||||
return 0field
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
function empty() { }
|
||||
|
||||
function main() {
|
||||
empty();
|
||||
empty();
|
||||
}
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> (bool, bool) {
|
||||
return (true, false)
|
||||
return (true, false)
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
function test() -> bool {
|
||||
return true
|
||||
function one() -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
function main() -> bool {
|
||||
return test() && test()
|
||||
return one() && one()
|
||||
}
|
@ -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()
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
function one() -> u32 {
|
||||
return 1u32
|
||||
return 1u32
|
||||
}
|
||||
|
||||
function main() -> u32 {
|
||||
return one()
|
||||
return one()
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
function foo() -> field {
|
||||
return myGlobal
|
||||
return myGlobal
|
||||
}
|
||||
|
||||
function main() -> field {
|
||||
const myGlobal = 42field;
|
||||
return foo()
|
||||
const myGlobal = 42field;
|
||||
return foo()
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() {
|
||||
my_function();
|
||||
my_function();
|
||||
}
|
@ -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
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main(g: group) -> group {
|
||||
return g
|
||||
return g
|
||||
}
|
@ -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
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main() -> group {
|
||||
return 0group
|
||||
return 0group
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import test_import.foo as bar;
|
||||
|
||||
function main() -> u32 {
|
||||
return bar()
|
||||
return bar()
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import test_import.foo;
|
||||
|
||||
function main() -> u32 {
|
||||
return foo()
|
||||
return foo()
|
||||
}
|
@ -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
|
||||
}
|
@ -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()
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main(b: bool) -> bool {
|
||||
return b
|
||||
return b
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
function main(a: bool, b: bool) -> bool {
|
||||
return a || b
|
||||
return a || b
|
||||
}
|
3
compiler/tests/integers/i128/add.leo
Normal file
3
compiler/tests/integers/i128/add.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main(a: i128, b: i128) -> i128 {
|
||||
return a + b
|
||||
}
|
3
compiler/tests/integers/i128/assert_eq.leo
Normal file
3
compiler/tests/integers/i128/assert_eq.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main(a: i128, b: i128) {
|
||||
assert_eq!(a, b);
|
||||
}
|
3
compiler/tests/integers/i128/div.leo
Normal file
3
compiler/tests/integers/i128/div.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main(a: i128, b: i128) -> i128 {
|
||||
return a / b
|
||||
}
|
3
compiler/tests/integers/i128/eq.leo
Normal file
3
compiler/tests/integers/i128/eq.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main(a: i128, b: i128) -> bool {
|
||||
return a == b
|
||||
}
|
3
compiler/tests/integers/i128/ge.leo
Normal file
3
compiler/tests/integers/i128/ge.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main(a: i128, b: i128) -> bool {
|
||||
return a >= b
|
||||
}
|
3
compiler/tests/integers/i128/gt.leo
Normal file
3
compiler/tests/integers/i128/gt.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main(a: i128, b: i128) -> bool {
|
||||
return a > b
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user