Data Types
Primitive Types
Addresses
Addresses are defined to enable compiler-optimized routines for parsing and operating over addresses. These semantics will be accompanied by a standard library in a future sprint.
let sender: address = aleo1ezamst4pjgj9zfxqq0fwfj8a4cjuqndmasgata3hggzqygggnyfq6kmyd4;
let receiver = aleo129nrpl0dxh4evdsan3f4lyhz5pdgp6klrn5atp37ejlavswx5czsk0j5dj;
Booleans
Leo supports the traditional true or false boolean values.
let b: bool = false;
let a = false
Integers
Leo supports signed integer types i8, i16, i32, i64, i128
and unsigned integer types u8, u16, u32, u64, u128.
let b: u8 = 1u8;
Underscores _ can be used to separate digits in integer literals.
let n: u64 = 1_000_000u64;
Higher bit length integers generate more constraints in the circuit, which can slow down computation time.
Leo does not assume a default integer type. Every integer must either have an explicit type annotation or a type that can be inferred by the compiler.
let a: u8 = 2u8; // explicit type
let b: u16 = a as u16; // type casting
Field Elements
Leo supports the field type for elements of the base field of the elliptic curve.
These are unsigned integers less than the modulus of the base field. The following are the smallest and largest field elements.
let a: field = 0field;
let b = 8444461749428370424248824938781546531375899335154063827935233455917409239040field;
let c: field = 0;
Group Elements
The set of affine points on the elliptic curve forms a group.
The curve is a Twisted Edwards curve with a = -1 and d = 3021.
Leo supports a subgroup of the group, generated by a generator point, as a primitive data type.
A group element is denoted by the x-coordinate of its point; for example,
2group means the point (2, 5553594316923449299484601589326170487897520766531075014687114064346375156608).
let a: group = 0group; // the point with 0 x-coordinate, (0, 1)
let b = 1540945439182663264862696551825005342995406165131907382295858612069623286213group; // the generator point
let c: group = 0;
The aforementioned generator point can be obtained via a constant associated to the group type.
let g: group = group::GEN; // the group generator
Scalar Elements
Leo supports the scalar type for elements of the scalar field defined by the elliptic curve subgroup.
These are unsigned integers less than the modulus of the scalar field. The following are the smallest and largest scalars.
let a: scalar = 0scalar;
let b = 2111115437357092606062206234695386632838870926408408195193685246394721360382scalar;
let c: scalar = 0;
Signatures
Aleo uses the Schnorr signature scheme to sign messages with an Aleo private key.
Signatures are a native type in Leo, and can be declared with the keyword signature.
Signatures can be verified in Leo using the signature::verify or s.verify operators.
program test.aleo {
struct foo {
a: u8,
b: scalar
}
transition verify_field(s: signature, a: address, v: field) {
let first: bool = signature::verify(s, a, v);
let second: bool = s.verify(a, v);
assert_eq(first, second);
}
transition verify_foo(s: signature, a: address, v: foo) {
let first: bool = signature::verify(s, a, v);
let second: bool = s.verify(a, v);
assert_eq(first, second);
}
}
Composite Types
Arrays
Leo supports static arrays. Array types are declared as [type; length] and can be nested.
Arrays only support constant accesses. The accessor expression must be a constant expression.
Arrays can contain primitive data types, structs, or arrays. Structs and records can also contain arrays.
Arrays can be iterated over using a for loop.
// Initalize a boolean array of length 4
let arr: [bool; 4] = [true, false, true, false];
// Nested array
let nested: [[bool; 2]; 2] = [[true, false], [true, false]];
// Empty array
let empty: [u32; 0] = [];
struct Bar {
data: u8,
}
// Array of structs
let arr_of_structs: [Bar; 2] = [Bar { data: 1u8 }, Bar { data: 2u8 }];
// Access the field of a struct within an array
transition foo(a: [Bar; 8]) -> u8 {
return a[0u8].data;
}
// Struct that contains an array
struct Bat {
data: [u8; 8],
}
// Record that contains an array
record Floo {
owner: address,
data: [u8; 8],
}
// Declare a mapping that contains array values
mapping data: address => [bool; 8];
// Iterate over an array using a for loop and sum the values within
transition sum_with_loop(a: [u64; 4]) -> u64 {
let sum: u64 = 0u64;
for i: u8 in 0u8..4u8 {
sum += a[i];
}
return sum;
}
Tuples
Leo supports tuples. Tuple types are declared as (type1, type2, ...) and can be nested. Tuples cannot be empty.
Tuples only support constant access with a dot . and a constant integer.
Tuples can contain primitive data types, structs, or arrays. Structs and records can also contain tuples.
program test.aleo {
transition baz(foo: u8, bar: u8) -> u8 {
let a: (u8, u8) = (foo, bar);
let result: u8 = a.0 + a.1;
return result;
}
}
Structs
Struct types are declared and constructed with a familiar syntax. Note that there is a global namespace for struct
types across your program and its dependencies. If a dependency declares a struct type T, you may access that type
without any qualifier.
program test.aleo {
struct S {
x: field,
y: u32,
}
transition foo(y: u32) -> S {
let s: S = S {
x: 172field,
y,
};
return s;
}
}
As of v3.0.0, Leo now supports const generics for struct types:
struct Matrix::[N: u32, M: u32] {
data: [field; N * M],
}
// Usage
let m = Matrix::[2, 2] { data: [0, 1, 2, 3] };
Note that generic structs cannot currently be imported outside a program, but can be declared and used in submodules. Acceptable types for const generic parameters include integer types, bool, scalar, group, field, and address.
Records
A record data type is the method of encoding private state on Aleo. Records are declared as record {name} {}. A record name must not contain the keyword aleo, and must not be a prefix of any other record name.
Records contain component declarations {visibility} {name}: {type},. Names of record components must not contain the keyword aleo. The visibility qualifier may be specified as constant, public, or private. If no qualifier is provided, Leo defaults to private.
Record data structures must always contain a component named owner of type address, as shown below. When passing a record as input to a program function, the _nonce: group and _version: u8 components are also required but do not need to be declared in the Leo program. They are inserted automatically by the compiler.
record Token {
// The token owner.
owner: address,
// The token amount.
amount: u64,
}
Option Types
As of v3.3.0, Leo supports first-class option types using the T? syntax, where T is any of the types previously mentioned, excluding record, address, signature, and tuple. A value of type T? can be initialized into two states: either a value of type T, or none:
let w: u8? = 42u8;
let x: u8? = none;
A value of type T? can be converted to type T by calling the .unwrap() method on the value. Note that if the value being unwrapped is none, then the program will fail to execute. To unwrap the value with a fallback for this case, call the .unwrap_or() method:
let y = w.unwrap(); // Returns 42u8
let z = x.unwrap_or(99u8); // Returns 99u8
Option types can also be stored in arrays and structs:
// Struct of options
struct Point {
x: u32?,
y: u32?
}
// Array of options
let arr: [u16?; 2] = [1u16, none];
let first_val = arr[0].unwrap(); // Returns 1u16
let second_val = arr[1].unwrap_or(0u16); // Returns 0u16
// Structs have option variant as well
let p: Point? = none;
let p_val = p.unwrap_or(Point { x: 0u32, y: none }); // Returns default
Type Inference
As of v2.7.0, Leo supports type inference. The Leo compiler is able to infer the types of declared variables and expressions as long as the type can be unambiguously determined from the surrounding context.
If the compiler cannot infer the type, you must provide an explicit type annotation.
Here are some examples:
let a: u8 = 2u8; // explicit type - allowed
let b = 2u8; // type inference - allowed
let c : u8 = 2; // type inference - allowed
let d = 2; // ambiguous type - not allowed
Type inference also applies to members within a struct:
struct Foo {
x: u8
}
let f = Foo {
x: 5, // inferred to be a `u8`
};