Standard Operators
Table of Contents
| Name | Description |
|---|---|
| abs | Absolute value |
| abs_wrapped | Wrapping absolute value |
| add | Addition |
| add_wrapped | Wrapping addition |
| and | Conjunction |
| assert | Assert boolean true |
| assert_eq | Assert equality |
| assert_neq | Assert non-equality |
| block.height | Fetch the latest block height |
| block.timestamp | Fetch the latest block timestamp |
| Deserialize:from_bits::[TYPE] | Deserialize bits to a data type |
| div | Division |
| div_wrapped | Wrapping division operation |
| double | Double |
| group::GEN | group generator |
| gt | Greater than comparison |
| gte | Greater than or equal to comparison |
| inv | Multiplicative inverse |
| eq | Equality comparison |
| neq | Non-equality comparison |
| lt | Less than comparison |
| lte | Less than or equal to comparison |
| mod | Modulo |
| mul | Multiplication |
| mul_wrapped | Wrapping multiplication |
| nand | Negated conjunction |
| neg | Additive inverse |
| nor | Negated disjunction |
| not | Logical negation |
| or | (Inclusive) disjunction |
| pow | Exponentiation |
| pow_wrapped | Wrapping exponentiation |
| rem | Remainder |
| rem_wrapped | Wrapping remainder |
| self.address | Address of the current program |
| self.caller | Address of a transition's calling user/program |
| self.checksum | Checksum of a program |
| self.edition | Version number of a program |
| self.program_owner | Address that submitted a program's deployment transaction |
| self.signer | Address of the top-level transition's calling user |
| Serialize::to_bits | Serialize data to bits |
| shl | Shift left |
| shl_wrapped | Wrapping shift left |
| shr | Shift right |
| shr_wrapped | Wrapping shift right |
| square_root | Square root |
| square | Square |
| sub | Subtraction |
| sub_wrapped | Wrapping subtraction |
| ternary | Ternary select |
| to_x_coordinate | Extract x-coordinate of a group element |
| to_y_coordinate | Extract y-coordinate of a group element |
| xor | Exclusive conjunction |
Arithmetic Operators
abs
let a: i8 = -1i8;
let b: i8 = a.abs(); // 1i8
Computes the absolute value of the input, checking for overflow, storing the result in the destination.
Note that execution will halt if the operation overflows. For cases where wrapping semantics are needed, see the abs_wrapped instruction. This overflow happens when the input is the minimum value of a signed integer type. For example, abs -128i8 would result in overflow, since 128 cannot be represented as an i8.
Supported Types
| Input | Destination |
|---|---|
i8 | i8 |
i16 | i16 |
i32 | i32 |
i64 | i64 |
i128 | i128 |
abs_wrapped
let a: i8 = -128i8;
let b: i8 = a.abs_wrapped(); // -128i8
Compute the absolute value of the input, wrapping around at the boundary of the type, and storing the result in the destination.
Supported Types
| Input | Destination |
|---|---|
i8 | i8 |
i16 | i16 |
i32 | i32 |
i64 | i64 |
i128 | i128 |
add
let a: u8 = 1u8;
let b: u8 = a + 1u8; // 2u8
let c: u8 = b.add(1u8); // 3u8
Adds first with second, storing the result in destination.
Note that execution will halt if the operation overflows. For cases where wrapping semantics are needed for integer types, see the add_wrapped instruction.
Supported Types
| First | Second | Destination |
|---|---|---|
field | field | field |
group | group | group |
i8 | i8 | i8 |
i16 | i16 | i16 |
i32 | i32 | i32 |
i64 | i64 | i64 |
i128 | i128 | i128 |
u8 | u8 | u8 |
u16 | u16 | u16 |
u32 | u32 | u32 |
u64 | u64 | u64 |
u128 | u128 | u128 |
scalar | scalar | scalar |
add_wrapped
let a: u8 = 255u8;
let b: u8 = a.add_wrapped(1u8); // 0u8
Adds first with second, wrapping around at the boundary of the type, and storing the result in destination.
Supported Types
| First | Second | Destination |
|---|---|---|
i8 | i8 | i8 |
i16 | i16 | i16 |
i32 | i32 | i32 |
i64 | i64 | i64 |
i128 | i128 | i128 |
u8 | u8 | u8 |
u16 | u16 | u16 |
u32 | u32 | u32 |
u64 | u64 | u64 |
u128 | u128 | u128 |
div
let a: u8 = 4u8;
let b: u8 = a / 2u8; // 2u8
let c: u8 = b.div(2u8); // 1u8
Performs division of the first operand by the second, storing the result in the destination. The operation halts if division by zero is attempted.
For integer types, this operation performs truncated division. Truncated division rounds towards zero, regardless of the sign of the operands. This means it cuts off any digits after the decimal, leaving the whole number whose absolute value is less than or equal to the result.
For example:
7 / 3yields2, not2.3333.-7 / 3yields-2, not-2.3333.
The operation halts if there is an underflow. Underflow occurs when dividing the minimum value of a signed integer type by -1. For example, -128i8 / -1i8 would result in underflow, since 128 cannot be represented as an i8.
For field types, division a / b is well-defined for any field values a and b except when b = 0field.
For cases where wrapping semantics are needed for integer types, see the div_wrapped instruction.
Supported Types
| First | Second | Destination |
|---|---|---|
field | field | field |
i8 | i8 | i8 |
i16 | i16 | i16 |
i32 | i32 | i32 |
i64 | i64 | i64 |
i128 | i128 | i128 |
u8 | u8 | u8 |
u16 | u16 | u16 |
u32 | u32 | u32 |
u64 | u64 | u64 |
u128 | u128 | u128 |
div_wrapped
let a: i8 = -128i8;
let b: i8 = a.div_wrapped(-1i8); // -128i8
Divides first by second, wrapping around at the boundary of the type, and storing the result in destination. Halts if second is zero.
Supported Types
| First | Second | Destination |
|---|---|---|
i8 | i8 | i8 |
i16 | i16 | i16 |
i32 | i32 | i32 |
i64 | i64 | i64 |
i128 | i128 | i128 |
u8 | u8 | u8 |
u16 | u16 | u16 |
u32 | u32 | u32 |
u64 | u64 | u64 |
u128 | u128 | u128 |
mod
let a: u8 = 3u8.mod(2u8); // 1u8
Takes the modulo of first with respect to second, storing the result in destination. Halts if second is zero.
The semantics of this operation are consistent with the mathematical definition of modulo operation.
mod ensures the remainder has the same sign as the second operand. This differs from rem, which follows truncated division and takes the sign of the first operand.
Supported Types
| First | Second | Destination |
|---|---|---|
u8 | u8 | u8 |
u16 | u16 | u16 |
u32 | u32 | u32 |
u64 | u64 | u64 |
u128 | u128 | u128 |
mul
let a: u8 = 2u8 * 2u8; // 4u8
let b: u8 = a.mul(2u8); // 8u8
Multiplies first with second, storing the result in destination.
Note that execution will halt if the operation overflows/underflows. For cases where wrapping semantics are needed for integer types, see the mul_wrapped instruction.
Supported Types
| First | Second | Destination |
|---|---|---|
field | field | field |
group | scalar | group |
scalar | group | group |
i8 | i8 | i8 |
i16 | i16 | i16 |
i32 | i32 | i32 |
i64 | i64 | i64 |
i128 | i128 | i128 |
u8 | u8 | u8 |
u16 | u16 | u16 |
u32 | u32 | u32 |
u64 | u64 | u64 |
u128 | u128 | u128 |
mul_wrapped
let a: u8 = 128u8.mul_wrapped(2u8); // 0u8
Multiplies first with second, wrapping around at the boundary of the type, and storing the result in destination.
Supported Types
| First | Second | Destination |
|---|---|---|
i8 | i8 | i8 |
i16 | i16 | i16 |
i32 | i32 | i32 |
i64 | i64 | i64 |
i128 | i128 | i128 |
u8 | u8 | u8 |
u16 | u16 | u16 |
u32 | u32 | u32 |
u64 | u64 | u64 |
u128 | u128 | u128 |
neg
let a: i8 = -1i8.neg(); // 1i8
Negates the first operand, storing the result in the destination.
For signed integer types, the operation halts if the minimum value is negated. For example, -128i8.neg() halts since 128 cannot be represented as an i8.
Supported Types
| Input | Destination |
|---|---|
field | field |
group | group |
i8 | i8 |
i16 | i16 |
i32 | i32 |
i64 | i64 |
i128 | i128 |
pow
let a: u8 = 2u8 ** 2u8; // 4u8
let b: u8 = a.pow(2u8); // 16u8
Raises first to the power of second, storing the result in destination.
Note that execution will halt if the operation overflows/underflows. For cases where wrapping semantics are needed for integer types, see the pow_wrapped instruction.
Supported Types
Magnitude can be a u8, u16, or u32.
| First | Second | Destination |
|---|---|---|
field | field | field |
i8 | Magnitude | i8 |
i16 | Magnitude | i16 |
i32 | Magnitude | i32 |
i64 | Magnitude | i64 |
i128 | Magnitude | i128 |
u8 | Magnitude | u8 |
u16 | Magnitude | u16 |
u32 | Magnitude | u32 |
u64 | Magnitude | u64 |
u128 | Magnitude | u128 |
pow_wrapped
let a: u8 = 16u8.pow_wrapped(2u8); // 0u8
Raises first to the power of second, wrapping around at the boundary of the type, storing the result in destination.
Supported Types
Magnitude can be a u8, u16, or u32.
| First | Second | Destination |
|---|---|---|
i8 | Magnitude | i8 |
i16 | Magnitude | i16 |
i32 | Magnitude | i32 |
i64 | Magnitude | i64 |
i128 | Magnitude | i128 |
u8 | Magnitude | u8 |
u16 | Magnitude | u16 |
u32 | Magnitude | u32 |
u64 | Magnitude | u64 |
u128 | Magnitude | u128 |
rem
let a: u8 = 3u8 % 2u8; // 1u8
let b: u8 = 4u8.rem(2u8); // 0u8
Computes the remainder of the division of the first operand by the second, storing the result in destination following truncated division rules:
a and b refers to first and second respectively
a % b = a - (a / b) * b
Here, a and b refer to the first and second operands, respectively
Note that execution will halt if the operation underflows or divides by zero. This underflow happens when the associated division operation, div, underflows.
For cases where wrapping semantics are needed for integer types, see the rem_wrapped instruction.
rem follows truncated division, meaning the remainder has the same sign as a. This differs from mod, where the remainder matches the sign of b.
Supported Types
| First | Second | Destination |
|---|---|---|
i8 | i8 | i8 |
i16 | i16 | i16 |
i32 | i32 | i32 |
i64 | i64 | i64 |
i128 | i128 | i128 |
u8 | u8 | u8 |
u16 | u16 | u16 |
u32 | u32 | u32 |
u64 | u64 | u64 |
u128 | u128 | u128 |
rem_wrapped
let a: i8 = -128i8;
let b: i8 = a.rem_wrapped(-1i8); // 0i8
Computes the remainder of the division of the first operand by the second following truncated division rules, storing the result in destination. Halts on division by zero.
Unlike rem, rem_wrapped is always defined and does not halt, even when div would wrap around.
Notably, rem_wrapped does not introduce wrapping itself but ensures the operation remains defined where rem would be undefined.
Supported Types
| First | Second | Destination |
|---|---|---|
i8 | i8 | i8 |
i16 | i16 | i16 |
i32 | i32 | i32 |
i64 | i64 | i64 |
i128 | i128 | i128 |
u8 | u8 | u8 |
u16 | u16 | u16 |
u32 | u32 | u32 |
u64 | u64 | u64 |
u128 | u128 | u128 |
sub
let a: u8 = 2u8 - 1u8; // 1u8
let b: u8 = a.sub(1u8); // 0u8
Computes first - second, storing the result in destination. The operation halts if the result is negative in an unsigned type or if it exceeds the minimum representable value in a signed type.
Supported Types
| First | Second | Destination |
|---|---|---|
field | field | field |
group | group | group |
i8 | i8 | i8 |
i16 | i16 | i16 |
i32 | i32 | i32 |
i64 | i64 | i64 |
i128 | i128 | i128 |
u8 | u8 | u8 |
u16 | u16 | u16 |
u32 | u32 | u32 |
u64 | u64 | u64 |
u128 | u128 | u128 |
sub_wrapped
let a: u8 = 0u8.sub_wrapped(1u8); // 255u8
Computes first - second, wrapping around at the boundary of the type, and storing the result in destination.
Supported Types
| First | Second | Destination |
|---|---|---|
i8 | i8 | i8 |
i16 | i16 | i16 |
i32 | i32 | i32 |
i64 | i64 | i64 |
i128 | i128 | i128 |
u8 | u8 | u8 |
u16 | u16 | u16 |
u32 | u32 | u32 |
u64 | u64 | u64 |
u128 | u128 | u128 |
Boolean/Bitwise Operators
and
// Integer (bitwise) AND
let a: i8 = 1i8 & 1i8;
let b: i8 = 1i8.and(2i8);
// Boolean (logical) AND
let a: bool = true && true;
let b: bool = true.and(false);
Performs an AND operation on integer (bitwise) or boolean first and second,
storing the result in destination.
Supported Types
| First | Second | Destination |
|---|---|---|
bool | bool | bool |
i8 | i8 | i8 |
i16 | i16 | i16 |
i32 | i32 | i32 |
i64 | i64 | i64 |
i128 | i128 | i128 |
u8 | u8 | u8 |
u16 | u16 | u16 |
u32 | u32 | u32 |
u64 | u64 | u64 |
u128 | u128 | u128 |
nand
let a: bool = true.nand(false); // true
Calculates the negated conjunction of first and second, storing the result in destination.
The result is false if and only if both first and second are true.
Supported Types
| First | Second | Destination |
|---|---|---|
bool | bool | bool |
nor
let a: bool = false.nor(false); // true
Calculates the negated (inclusive) disjunction of first and second, storing the result in destination. The result is true if and only if both first and second are false.
Supported Type
| First | Second | Destination |
|---|---|---|
bool | bool | bool |
not
let a: bool = true.not(); // false
Perform a NOT operation on an integer (bitwise) or boolean input, storing the result in destination.
Supported Types
| Input | Destination |
|---|---|
bool | bool |
i8 | i8 |
i16 | i16 |
i32 | i32 |
i64 | i64 |
i128 | i128 |
u8 | u8 |
u16 | u16 |
u32 | u32 |
u64 | u64 |
u128 | u128 |
or
// Integer (bitwise) OR
let a: i8 = 1i8 | 2i8;
let b: i8 = 1i8.or(2i8);
// Boolean (logical) OR
let a: bool = true || true;
let b: bool = true.or(false);
Performs an inclusive OR operation on integer (bitwise) or boolean first and second, storing the result in destination.
Supported Types
| First | Second | Destination |
|---|---|---|
bool | bool | bool |
i8 | i8 | i8 |
i16 | i16 | i16 |
i32 | i32 | i32 |
i64 | i64 | i64 |
i128 | i128 | i128 |
u8 | u8 | u8 |
u16 | u16 | u16 |
u32 | u32 | u32 |
u64 | u64 | u64 |
u128 | u128 | u128 |
shl
let a: u8 = 1u8 << 1u8; // 2u8
let b: u8 = a.shl(1u8); // 4u8
Shifts first left by second bits, storing the result in destination. The operation halts if the shift distance exceeds the bit size of first, or if the shifted result does not fit within the type of first.
Supported Types
Magnitude can be a u8, u16, or u32.
| First | Second | Destination |
|---|---|---|
i8 | Magnitude | i8 |
i16 | Magnitude | i16 |
i32 | Magnitude | i32 |
i64 | Magnitude | i64 |
i128 | Magnitude | i128 |
u8 | Magnitude | u8 |
u16 | Magnitude | u16 |
u32 | Magnitude | u32 |
u64 | Magnitude | u64 |
u128 | Magnitude | u128 |
shl_wrapped
let a: u8 = 128u8.shl_wrapped(1u8); // 0u8
let b: i8 = 64i8.shl_wrapped(2u8); // -128i8
Shifts first left by second bits, wrapping around at the boundary of the type, storing the result in destination. The shift distance is masked to the bit width of first, ensuring that shifting by n is equivalent to shifting by n % bit_size.
If bits are shifted beyond the type's range, they are discarded, which may cause sign changes for signed integers.
Supported Types
Magnitude can be a u8, u16, or u32.
| First | Second | Destination |
|---|---|---|
i8 | Magnitude | i8 |
i16 | Magnitude | i16 |
i32 | Magnitude | i32 |
i64 | Magnitude | i64 |
i128 | Magnitude | i128 |
u8 | Magnitude | u8 |
u16 | Magnitude | u16 |
u32 | Magnitude | u32 |
u64 | Magnitude | u64 |
u128 | Magnitude | u128 |
shr
let a: u8 = 4u8 >> 1u8; // 2u8
let b: u8 = a.shr(1u8); // 1u8
Shifts first right by second bits, storing the result in destination. The operation halts if the shift distance exceeds the bit size of first.
Supported Types
Magnitude can be a u8, u16, or u32.
| First | Second | Destination |
|---|---|---|
i8 | Magnitude | i8 |
i16 | Magnitude | i16 |
i32 | Magnitude | i32 |
i64 | Magnitude | i64 |
i128 | Magnitude | i128 |
u8 | Magnitude | u8 |
u16 | Magnitude | u16 |
u32 | Magnitude | u32 |
u64 | Magnitude | u64 |
u128 | Magnitude | u128 |
shr_wrapped
let a: u8 = 128u8.shr_wrapped(7u8); // 1u8
Shifts first right by second bits, wrapping around at the boundary of the type, storing the result in destination. The shift distance is masked to the bit width of first, ensuring that shifting by n is equivalent to shifting by n % bit_size.
Supported Types
Magnitude can be a u8, u16, or u32.
| First | Second | Destination |
|---|---|---|
i8 | Magnitude | i8 |
i16 | Magnitude | i16 |
i32 | Magnitude | i32 |
i64 | Magnitude | i64 |
i128 | Magnitude | i128 |
u8 | Magnitude | u8 |
u16 | Magnitude | u16 |
u32 | Magnitude | u32 |
u64 | Magnitude | u64 |
u128 | Magnitude | u128 |
xor
let a: bool = true.xor(false); // true
Performs a XOR operation on integer (bitwise) or boolean first and second, storing the result in destination.
Supported Types
| First | Second | Destination |
|---|---|---|
bool | bool | bool |
i8 | i8 | i8 |
i16 | i16 | i16 |
i32 | i32 | i32 |
i64 | i64 | i64 |
i128 | i128 | i128 |
u8 | u8 | u8 |
u16 | u16 | u16 |
u32 | u32 | u32 |
u64 | u64 | u64 |
u128 | u128 | u128 |
Comparators
gt
let a: bool = 2u8 > 1u8; // true
let b: bool = 1u8.gt(1u8); // false
Checks if first is greater than second, storing the result in destination.
Supported Types
| First | Second | Destination |
|---|---|---|
field | field | bool |
i8 | i8 | bool |
i16 | i16 | bool |
i32 | i32 | bool |
i64 | i64 | bool |
i128 | i128 | bool |
u8 | u8 | bool |
u16 | u16 | bool |
u32 | u32 | bool |
u64 | u64 | bool |
u128 | u128 | bool |
scalar | scalar | bool |
gte
let a: bool = 2u8 >= 1u8; // true
let b: bool = 1u8.gte(1u8); // true
Checks if first is greater than or equal to second, storing the result in destination.
Supported Types
| First | Second | Destination |
|---|---|---|
field | field | bool |
i8 | i8 | bool |
i16 | i16 | bool |
i32 | i32 | bool |
i64 | i64 | bool |
i128 | i128 | bool |
u8 | u8 | bool |
u16 | u16 | bool |
u32 | u32 | bool |
u64 | u64 | bool |
u128 | u128 | bool |
scalar | scalar | bool |
eq
let a: bool = 1u8 == 1u8; // true
let b: bool = 1u8.eq(2u8); // false
Compares first and second for equality, storing the result in destination.
Supported Types
| First | Second | Destination |
|---|---|---|
address | address | bool |
bool | bool | bool |
field | field | bool |
group | group | bool |
i8 | i8 | bool |
i16 | i16 | bool |
i32 | i32 | bool |
i64 | i64 | bool |
i128 | i128 | bool |
u8 | u8 | bool |
u16 | u16 | bool |
u32 | u32 | bool |
u64 | u64 | bool |
u128 | u128 | bool |
scalar | scalar | bool |
Signature | Signature | bool |
struct | struct | bool |
Record | Record | bool |
neq
let a: bool = 1u8 != 1u8; // false
let b: bool = 1u8.neq(2u8); // true
Compares first and second for non-equality, storing the result in destination.
Supported Types
| First | Second | Destination |
|---|---|---|
address | address | bool |
bool | bool | bool |
field | field | bool |
group | group | bool |
i8 | i8 | bool |
i16 | i16 | bool |
i32 | i32 | bool |
i64 | i64 | bool |
i128 | i128 | bool |
u8 | u8 | bool |
u16 | u16 | bool |
u32 | u32 | bool |
u64 | u64 | bool |
u128 | u128 | bool |
scalar | scalar | bool |
Signature | Signature | bool |
struct | struct | bool |
Record | Record | bool |
lt
let a: bool = 1u8 < 2u8; // true
let b: bool = 1u8.lt(1u8); // false
Checks if first is less than second, storing the result in destination.
Supported Types
| First | Second | Destination |
|---|---|---|
field | field | bool |
i8 | i8 | bool |
i16 | i16 | bool |
i32 | i32 | bool |
i64 | i64 | bool |
i128 | i128 | bool |
u8 | u8 | bool |
u16 | u16 | bool |
u32 | u32 | bool |
u64 | u64 | bool |
u128 | u128 | bool |
scalar | scalar | bool |
lte
let a: bool = 1u8 <= 2u8; // true
let b: bool = 1u8.lte(1u8); // true
Checks if first is less than or equal to second, storing the result in destination.
Supported Types
| First | Second | Destination |
|---|---|---|
field | field | bool |
i8 | i8 | bool |
i16 | i16 | bool |
i32 | i32 | bool |
i64 | i64 | bool |
i128 | i128 | bool |
u8 | u8 | bool |
u16 | u16 | bool |
u32 | u32 | bool |
u64 | u64 | bool |
u128 | u128 | bool |
scalar | scalar | bool |
Context-dependent Expressions
block.height
async transition matches(height: u32) -> Future {
return check_block_height(height);
}
async function check_block_height(height: u32) {
assert_eq(height, block.height);
}
The block.height operator is used to fetch the latest block height in a Leo program. It represents the number of
blocks in the chain. In the above example, block.height is used in an async function to fetch the latest block
height in a program.
- The
block.heightoperator can only be used in an async function. Using it outside an async function will result in a compilation error. - The
block.heightoperator doesn't take any parameters.
block.timestamp
async transition matches(timestamp: i64) -> Future {
return check_block_timestamp(timestamp);
}
async function check_block_timestamp(timestamp: i64) {
assert_eq(timestamp, block.timestamp);
}
The block.timestamp operator is used to fetch the timestamp of the latest block in a Leo program. It represents the number of
UNIX timestamp of the latest block in the chain. In the above example, block.timestamp is used in an async function to fetch the latest block
height in a program.
- The
block.timestampoperator can only be used in an async function. Using it outside an async function will result in a compilation error. - The
block.timestampoperator doesn't take any parameters.
self.address
transition get_program_address() -> address {
return self.address;
}
The self.address operator returns the address of the program that calls it. While programs are identified by their name ({PROGRAM_NAME}.aleo), under the hood they have a corresponding Aleo address.
- The
self.addressoperator doesn't take any parameters.
self.caller
transition matches(addr: address) -> bool {
return self.caller == addr;
}
The self.caller operator returns the address of the account/program that invoked the current transition. Note that if the transition was called as part of an external program, this operation will return the address of the program, NOT the address of the top-level user.
- The
self.calleroperator doesn't take any parameters.
self.checksum
async transition matches(checksum: [u8,32]) -> Future {
return check_program_checksum(checksum);
}
async function check_program_checksum(checksum: [u8,32]) {
assert_eq(self.checksum, checksum);
}
The self.checksum operator returns a program's checksum, which is a unique identifier for the program's code.
You may also refer to another program's checksum with the following syntax:
import credits.aleo;
...
let ext_checksum: [u8, 32] = Program::checksum(credits.aleo);
- The
self.checksumoperator can only be used in an async function. Using it outside an async function will result in a compilation error. - The
self.checksumoperator doesn't take any parameters. - To reference another program's checksum, you will need to import that program first.
self.edition
async transition matches(edition: u16) -> Future {
return check_program_edition(edition);
}
async function check_program_edition(edition: u16) {
assert_eq(self.edition, edition);
}
The self.edition operator returns a program's edition, which is the program's version number. A program's edition starts at zero and is incremented by one for each upgrade. The edition is tracked automatically on the network.
You may also refer to another program's edition with the following syntax:
import credits.aleo;
...
let ext_edition: u16 = Program::edition(credits.aleo);
- The
self.editionoperator can only be used in an async function. Using it outside an async function will result in a compilation error. - The
self.editionoperator doesn't take any parameters. - To reference another program's edition, you will need to import that program first.
self.program_owner
async transition matches(owner: address) -> Future {
return check_program_owner(owner);
}
async function check_program_owner(owner: address) {
assert_eq(self.program_owner, owner);
}
The self.program_owner operator returns the address that submitted the deployment transaction for a program.
You may also refer to another program's owner with the following syntax:
import credits.aleo;
...
let ext_owner: u16 = Program::owner(credits.aleo);
- The
self.program_owneroperator can only be used in an async function. Using it outside an async function will result in a compilation error. - The
self.program_owneroperator doesn't take any parameters. - To reference another program's owner, you will need to import that program first.
self.signer
transition matches(addr: address) -> bool {
return self.signer == addr;
}
The self.signer operator returns the address of the account/program that invoked the top-level transition. This will be the user account that signed the transaction.
- The
self.signeroperator doesn't take any parameters.
Group/Field Specific Operators
group::GEN
let g: group = group::GEN; // the group generator
Returns the generator of the algebraic group that the group type consists of.
The compilation of Leo is based on an elliptic curve, whose points form a group,
and on a specified point on that curve, which generates a subgroup, whose elements form the type group.
This is a constant, not a function. Thus, it takes no inputs, and just returns an output.
It is an associated constant, whose name is GEN and whose associated type is group.
Supported Types
| Destination |
|---|
group |
double
let a: group = 2group;
let b: group = a.double();
Adds the input to itself, storing the result in destination.
Supported Types
| Input | Destination |
|---|---|
field | field |
group | group |
inv
let a: field = 1field.inv();
Computes the multiplicative inverse of the input, storing the result in destination.
Supported Types
| Input | Destination |
|---|---|
field | field |
square
let a: field = 1field.square(); // 1field
Squares the input, storing the result in destination.
Supported Types
| Input | Destination |
|---|---|
field | field |
square_root
let a: field = 1field.square_root(); // 1field
Computes the square root of the input, storing the result in destination. If the input is a quadratic residue, the function returns the smaller of the two possible roots based on modular ordering. If the input is not a quadratic residue, execution halts.
Supported Types
| Input | Destination |
|---|---|
field | field |
to_x_coordinate
let x: field = 0group.to_x_coordinate(); // 0field
Extracts the x-coordinate of the group element as a field element.
Supported Types
| Input | Destination |
|---|---|
group | field |
to_y_coordinate
let y: field = 0group.to_y_coordinate(); // 1field
Extracts the y-coordinate of the group element as a field element.
Supported Types
| Input | Destination |
|---|---|
group | field |
Serialization / Deserialization
Serialize::to_bits
// Standard serialization (includes type metadata)
let bits: [bool; 58] = Serialize::to_bits(value);
// Raw serialization (no metadata, just raw bits)
let bits: [bool; 32] = Serialize::to_bits_raw(value);
// Works with arrays too
let bits: [bool; 128] = Serialize::to_bits_raw([1u32, 2u32, 3u32, 4u32]);
By appending _raw to the end of the function, the function will omit the metadata of a type and directly serialize the input bits.
Supported Types
| First | Destination | Destination (Raw) |
|---|---|---|
address | [bool; 279] | [bool; 253] |
bool | [bool; 27] | [bool; 1] |
field | [bool; 279] | [bool; 253] |
group | [bool; 279] | [bool; 253] |
i8 | [bool; 34] | [bool; 8] |
i16 | [bool; 42] | [bool; 16] |
i32 | [bool; 58] | [bool; 32] |
i64 | [bool; 90] | [bool; 64] |
i128 | [bool; 154] | [bool; 128] |
u8 | [bool; 34] | [bool; 8] |
u16 | [bool; 42] | [bool; 16] |
u32 | [bool; 58] | [bool; 32] |
u64 | [bool; 90] | [bool; 64] |
u128 | [bool; 154] | [bool; 128] |
scalar | [bool; 277] | [bool; 251] |
Deserialize::from_bits::[TYPE]
// Standard deserialization (includes type metadata)
let bits1: [bool; 58] = Serialize::to_bits(1u32);
let value1: u32 = Deserialize::from_bits::[u32](bits1);
// Raw deserialization (no metadata, just raw bits)
let bits2: [bool; 32] = Serialize::to_bits_raw(1u32);
let value2: u32 = Deserialize::from_bits_raw::[u32](bits2);
// Works with arrays too
let bits3: [bool; 128] = Serialize::to_bits_raw([1u32, 2u32, 3u32, 4u32]);
let arr: [u32; 4] = Deserialize::from_bits_raw::[[u32; 4]](bits3);
By appending _raw to the end of the function, the function will omit the metadata of a type and directly serialize the input bits.
Supported Types
| TYPE | Input | Input (Raw) | Destination |
|---|---|---|---|
address | [bool; 279] | [bool; 253] | address |
bool | [bool; 27] | [bool; 1] | bool |
field | [bool; 279] | [bool; 253] | field |
group | [bool; 279] | [bool; 253] | group |
i8 | [bool; 34] | [bool; 8] | i8 |
i16 | [bool; 42] | [bool; 16] | i16 |
i32 | [bool; 58] | [bool; 32] | i32 |
i64 | [bool; 90] | [bool; 64] | i64 |
i128 | [bool; 154] | [bool; 128] | i128 |
u8 | [bool; 34] | [bool; 8] | u8 |
u16 | [bool; 42] | [bool; 16] | u16 |
u32 | [bool; 58] | [bool; 32] | u32 |
u64 | [bool; 90] | [bool; 64] | u64 |
u128 | [bool; 154] | [bool; 128] | u128 |
scalar | [bool; 277] | [bool; 251] | scalar |
Miscellaneous
assert
let a: bool = true;
let b: bool = false;
assert(a); // will not halt
assert(b); // program halts
Checks whether the expression evaluates to a true boolean value, halting if evaluates to false.
Supported Types
| Expression |
|---|
bool |
assert_eq
let a: u8 = 1u8;
let b: u8 = 2u8;
assert_eq(a, a); // will not halt
assert_eq(a, b); // program halts
Checks whether first and second are equal, halting if they are not equal.
Supported Types
| First | Second |
|---|---|
address | address |
bool | bool |
field | field |
group | group |
i8 | i8 |
i16 | i16 |
i32 | i32 |
i64 | i64 |
i128 | i128 |
u8 | u8 |
u16 | u16 |
u32 | u32 |
u64 | u64 |
u128 | u128 |
scalar | scalar |
Signature | Signature |
struct | struct |
Record | Record |
assert_neq
let a: u8 = 1u8;
let b: u8 = 2u8;
assert_neq(a, b); // will not halt
assert_neq(a, a); // program halts
Checks whether first and second are not equal, halting if they are equal.
Supported Types
| First | Second |
|---|---|
address | address |
bool | bool |
field | field |
group | group |
i8 | i8 |
i16 | i16 |
i32 | i32 |
i64 | i64 |
i128 | i128 |
u8 | u8 |
u16 | u16 |
u32 | u32 |
u64 | u64 |
u128 | u128 |
scalar | scalar |
Signature | Signature |
struct | struct |
Record | Record |
ternary
let a: u8 = true ? 1u8 : 2u8; // 1u8
Selects first, if condition is true, otherwise selects second, storing the result in destination.
Supported Types
| Condition | First | Second | Destination |
|---|---|---|---|
bool | bool | bool | bool |
bool | field | field | field |
bool | group | group | group |
bool | i8 | i8 | i8 |
bool | i16 | i16 | i16 |
bool | i32 | i32 | i32 |
bool | i64 | i64 | i64 |
bool | i128 | i128 | i128 |
bool | u8 | u8 | u8 |
bool | u16 | u16 | u16 |
bool | u32 | u32 | u32 |
bool | u64 | u64 | u64 |
bool | u128 | u128 | u128 |
bool | scalar | scalar | scalar |
bool | Signature | Signature | Signature |