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 |
| Aleo::generator | Aleo group generator constant |
| Aleo::generator_powers | Precomputed Aleo generator powers [group; 251] |
| 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 |
| Program::checksum | Checksum of another (imported) program |
| Program::edition | Edition (version) of another (imported) program |
| Program::program_owner | Deployer address of another (imported) program |
| self.address | Address of the current program |
| self.caller | Address of the calling user/program |
| self.checksum | Checksum of a program |
| self.edition | Version number of a program |
| self.id | Address of the current program (alias of self.address) |
| self.program_owner | Address that submitted a program's deployment transaction |
| self.signer | Address of the top-level 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 c: bool = true && true;
let d: 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 c: bool = true || true;
let d: 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
fn matches_height(height: u32) -> Final {
return final {
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 a final { } block to fetch the latest block
height in a program.
- The
block.heightoperator can only be used in on-chain context — afinal { }block, afinal fn, or aconstructor. It is rejected in entryfnbodies, helperfns, and constant initialisers, since chain state is only observable in the finalization context. - The
block.heightoperator doesn't take any parameters.
block.timestamp
fn matches_timestamp(timestamp: i64) -> Final {
return final {
assert_eq(timestamp, block.timestamp);
};
}
The block.timestamp operator is used to fetch the UNIX timestamp of the latest block in a Leo program. In the above example, block.timestamp is used in a final { } block to fetch the latest block timestamp in a program.
- The
block.timestampoperator can only be used in on-chain context — afinal { }block, afinal fn, or aconstructor. It is rejected in entryfnbodies, helperfns, and constant initialisers, since chain state is only observable in the finalization context. - The
block.timestampoperator doesn't take any parameters.
self.address
fn 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 may be used in any function context (entryfn, helperfn,final fn,final { }block, orconstructor). - The
self.addressoperator doesn't take any parameters.
self.caller
fn matches_caller(addr: address) -> bool {
return self.caller == addr;
}
The self.caller operator returns the address of the account/program that invoked the current entry function. Note that if the function 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 can only be used in proof context — inside an entryfnbody or a helperfnbody, but not inside afinal { }block, afinal fn, or aconstructor. The notion of "the function's immediate caller" only exists in the proof context; finalization runs after the call has been validated. The compiler emits an error ifself.calleris used in an on-chain context. - The
self.calleroperator doesn't take any parameters.
self.checksum
fn matches_checksum(checksum: [u8; 32]) -> Final {
return final {
assert_eq(self.checksum, checksum);
};
}
The self.checksum operator returns the current program's checksum, which is a unique identifier for the program's code. To reference another program's checksum, see Program::checksum.
- The
self.checksumoperator may be used in any function context (entryfn, helperfn,final fn,final { }block, orconstructor). - The
self.checksumoperator doesn't take any parameters.
Program::checksum
let ext_checksum: [u8; 32] = Program::checksum(credits.aleo);
The Program::checksum operator returns the on-chain checksum of an imported program — the same value that program would observe with self.checksum. The argument must be a program-ID literal of the form name.aleo, not a runtime address.
Supported Types
| Argument | Destination |
|---|---|
| program ID literal | [u8; 32] |
- The
Program::checksum(other.aleo)operator can only be used in on-chain context — afinal { }block, afinal fn, or aconstructor. Using it elsewhere will result in a compilation error. - The argument must be a program-ID literal (e.g.
credits.aleo), not a variable typed asaddress. - To reference another program's checksum, you will need to import that program first.
self.edition
fn matches_edition(edition: u16) -> Final {
return final {
assert_eq(self.edition, edition);
};
}
The self.edition operator returns the current 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. To reference another program's edition, see Program::edition.
- The
self.editionoperator may be used in any function context (entryfn, helperfn,final fn,final { }block, orconstructor). - The
self.editionoperator doesn't take any parameters.
Program::edition
let ext_edition: u16 = Program::edition(credits.aleo);
The Program::edition operator returns the on-chain edition of an imported program — the same value that program would observe with self.edition. Useful for guarding logic against specific upgrade versions of a dependency. The argument must be a program-ID literal.
Supported Types
| Argument | Destination |
|---|---|
| program ID literal | u16 |
- The
Program::edition(other.aleo)operator can only be used in on-chain context — afinal { }block, afinal fn, or aconstructor. Using it elsewhere will result in a compilation error. - The argument must be a program-ID literal (e.g.
credits.aleo), not a variable typed asaddress. - To reference another program's edition, you will need to import that program first.
self.id
fn get_program_id() -> address {
return self.id;
}
The self.id operator returns the on-chain address of the program containing the call site. It is an alias of self.address and lowers to the same Aleo instruction; the alternate spelling reads more naturally when comparing program identifiers.
- The
self.idoperator may be used in any function context (entryfn, helperfn,final fn,final { }block, orconstructor). - The
self.idoperator doesn't take any parameters.
self.program_owner
fn matches_owner(owner: address) -> Final {
return final {
assert_eq(self.program_owner, owner);
};
}
The self.program_owner operator returns the address that submitted the deployment transaction for the current program. To reference another program's owner, see Program::program_owner.
- The
self.program_owneroperator can only be used in on-chain context — afinal { }block, afinal fn, or aconstructor. Using it elsewhere will result in a compilation error. - The
self.program_owneroperator doesn't take any parameters. - Programs deployed before the upgradability feature shipped (Leo
< v3.1.0) do not have aprogram_owner. Readingself.program_owneron such a program halts at runtime.
Program::program_owner
let ext_owner: address = Program::program_owner(credits.aleo);
The Program::program_owner operator returns the address that submitted the deployment transaction for an imported program — the same value that program would observe with self.program_owner. The argument must be a program-ID literal.
Supported Types
| Argument | Destination |
|---|---|
| program ID literal | address |
- The
Program::program_owner(other.aleo)operator can only be used in on-chain context — afinal { }block, afinal fn, or aconstructor. Using it elsewhere will result in a compilation error. - The argument must be a program-ID literal (e.g.
credits.aleo), not a variable typed asaddress. - To reference another program's owner, you will need to import that program first.
- If the target program was deployed before the upgradability feature shipped, this call halts at runtime.
self.signer
fn matches_signer(addr: address) -> bool {
return self.signer == addr;
}
The self.signer operator returns the address of the account that invoked the top-level entry function. This will be the user account that signed the transaction.
- The
self.signeroperator can only be used in proof context — inside an entryfnbody or a helperfnbody, but not inside afinal { }block, afinal fn, or aconstructor. Finalization values must be derived in proof context and passed forward as inputs. If you need the signer's address inside afinal { }block, capture it in proof context first and pass it as an argument to the finalize call. - 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 |
Aleo::generator
let g: group = Aleo::generator();
Returns the generator point of the Aleo group. This is equivalent to group::GEN but expressed through the Aleo namespace for consistency with the other Aleo::* operators. Like group::GEN, it is a constant that takes no inputs.
Supported Types
| Destination |
|---|
group |
Aleo::generator_powers
let powers: [group; 251] = Aleo::generator_powers();
Returns a precomputed array of the first 251 consecutive powers of the Aleo group generator: [G^0, G^1, G^2, ..., G^250]. Useful for efficient scalar multiplication without recomputing the powers at runtime.
The array always has exactly 251 elements. Indexing beyond 250u32 is rejected at compile time by Leo's array bounds check — there is no runtime halt specific to this operator.
Supported Types
| Destination |
|---|
[group; 251] |
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 value: u32 = 1u32;
let bits: [bool; 58] = Serialize::to_bits(value);
// Raw serialization (no metadata, just raw bits)
let bits2: [bool; 32] = Serialize::to_bits_raw(value);
// Works with arrays too
let bits3: [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 |