# 3.7 Operators

In this chapter, we'll explore operators and expressions in the Leo programming language. Leo offers a long list of operators for performing arithmetic operations, logical comparisons, bitwise manipulations, and cryptographic functions.

### Basic Concepts

Operators in Leo compute a value based on one or more expressions. Leo defaults to **checked arithmetic**. This means that operations like addition, subtraction, and multiplication will throw an error if an overflow or division by zero is detected.

Let's look at a simple example:

```rust
let a: u8 = 1u8 + 1u8;
// a is equal to 2

a += 1u8;
// a is now equal to 3

a = a.add(1u8);
// a is now equal to 4
```

This example demonstrates three different ways to perform addition in Leo:

* Using the `+` operator
* Using the `+=` compound assignment operator
* Using the `.add()` method

### Operator Precedence

When an expression contains multiple operators, Leo follows a strict order of evaluation based on operator precedence. Here's the complete precedence table, from highest (evaluated first) to lowest:

| Operator                                                       | Associativity |
| -------------------------------------------------------------- | ------------- |
| `!` `-`(unary)                                                 |               |
| `**`                                                           | right to left |
| `*` `/`                                                        | left to right |
| `+` `-`(binary)                                                | left to right |
| `<<` `>>`                                                      | left to right |
| `&`                                                            | left to right |
| `\|`                                                           | left to right |
| `^`                                                            | left to right |
| `<` `>` `<=` `>=`                                              |               |
| `==` `!=`                                                      | left to right |
| `&&`                                                           | left to right |
| `\|\|`                                                         | left to right |
| `=` `+=` `-=` `*=` `/=` `%=` `**=` `<<=` `>>=` `&=` `\|=` `^=` |               |

#### Using Parentheses for Explicit Ordering

To override the default precedence, you can use parentheses to explicitly control the order of evaluation:

```rust
let result = (a + 1u8) * 2u8;
```

In this example, `(a + 1u8)` will be evaluated first, then the result will be multiplied by `2u8`.

### Context-dependent Expressions

Leo supports special expressions that provide information about the Aleo blockchain and the current transaction.

#### self.caller

The `self.caller` expression returns the address of the account or program that invoked the current transition:

```rust
program test.aleo {
    transition matches(addr: address) -> bool {
        return self.caller == addr;
    }
}
```

#### self.signer

The `self.signer` expression returns the address of the account that invoked the top-level transition - the account that signed the transaction:

```rust
program test.aleo {
    transition matches(addr: address) -> bool {
        return self.signer == addr;
    }
}
```

#### block.height

The `block.height` expression returns the current block height. Note that this can only be used in an async function:

```rust
program test.aleo {
    async transition matches(height: u32) -> Future {
        return check_block_height(height);
    } 
    
    async function check_block_height(height: u32) {
        assert_eq(height, block.height);
    }
}
```

### Core Functions

Leo provides several built-in functions for assertions and cryptographic operations.

#### Assertions

The `assert` and `assert_eq` functions verify conditions and halt program execution if they fail:

```rust
program test.aleo {
    transition matches() {
        assert(true);            // Continues execution
        assert_eq(1u8, 1u8);     // Continues execution
        // assert(false);        // Would halt execution
        // assert_eq(1u8, 2u8);  // Would halt execution
    }
}
```

#### Hash Functions

Leo supports multiple hashing algorithms, each with different input sizes and output types:

```rust
let a: scalar = BHP256::hash_to_scalar(1u8);
let b: address = Pedersen64::hash_to_address(1u128);
let c: group = Poseidon2::hash_to_group(1field);
```

Available hashing algorithms include:

* BHP256, BHP512, BHP768, BHP1024
* Pedersen64, Pedersen128
* Poseidon2, Poseidon4, Poseidon8
* Keccak256, Keccak384, Keccak512
* SHA3\_256, SHA3\_384, SHA3\_512

#### Commitment Functions

Commitment schemes allow you to commit to a value while keeping it hidden, then reveal it later:

```rust
let salt: scalar = ChaCha::rand_scalar();
let a: group = BHP256::commit_to_group(1u8, salt);
let b: address = Pedersen64::commit_to_address(1u128, salt);
```

#### Random Number Generation

The ChaCha algorithm provides cryptographically secure random number generation. These functions can only be used in async functions:

```rust
let a: group = ChaCha::rand_group();
let b: u32 = ChaCha::rand_u32();
```

### Standard Operators

Let's explore the standard operators available in Leo in more detail.

#### Arithmetic Operators

**Addition (`+`, `add`, `add_wrapped`)**

```rust
// Regular checked addition
let a: u8 = 1u8 + 2u8;       // a = 3

// Method syntax for addition
let b: u8 = a.add(4u8);      // b = 7

// Wrapping addition (does not check for overflow)
let c: u8 = 255u8.add_wrapped(1u8);  // c = 0 (wraps around)
```

**Subtraction (`-`, `sub`, `sub_wrapped`)**

```rust
// Regular checked subtraction
let a: u8 = 5u8 - 2u8;       // a = 3

// Method syntax
let b: u8 = a.sub(1u8);      // b = 2

// Wrapping subtraction
let c: u8 = 0u8.sub_wrapped(1u8);  // c = 255 (wraps around)
```

**Multiplication (`*`, `mul`, `mul_wrapped`)**

```rust
// Regular checked multiplication
let a: u8 = 3u8 * 2u8;       // a = 6

// Method syntax
let b: u8 = a.mul(2u8);      // b = 12

// Wrapping multiplication
let c: u8 = 128u8.mul_wrapped(2u8);  // c = 0 (wraps around)
```

**Division (`/`, `div`, `div_wrapped`)**

```rust
// Regular checked division
let a: u8 = 8u8 / 2u8;       // a = 4

// Method syntax
let b: u8 = a.div(2u8);      // b = 2

// Wrapping division
// For signed integers, handles special cases like MIN_VALUE / -1
let c: i8 = (-128i8).div_wrapped(-1i8);  // c = -128 (would overflow in checked division)
```

**Exponentiation (`**`, `pow`, `pow_wrapped`)**

```rust
// Regular checked exponentiation
let a: u8 = 2u8 ** 3u8;      // a = 8

// Method syntax
let b: u8 = a.pow(2u8);      // b = 64

// Wrapping exponentiation
let c: u8 = 16u8.pow_wrapped(2u8);  // c = 0 (wraps around)
```

#### Comparison Operators

```rust
let a: u8 = 5u8;
let b: u8 = 10u8;

let eq: bool = a == b;      // false
let neq: bool = a != b;     // true
let lt: bool = a < b;       // true
let lte: bool = a <= b;     // true
let gt: bool = a > b;       // false
let gte: bool = a >= b;     // false
```

Method syntax is also available for these comparisons:

```rust
let eq: bool = a.eq(b);     // false
let neq: bool = a.neq(b);   // true
let lt: bool = a.lt(b);     // true
let lte: bool = a.lte(b);   // true
let gt: bool = a.gt(b);     // false
let gte: bool = a.gte(b);   // false
```

#### Logical Operators

```rust
let a: bool = true;
let b: bool = false;

let and: bool = a && b;     // false
let or: bool = a || b;      // true
let not: bool = !a;         // false
```

Method syntax:

```rust
let and: bool = a.and(b);   // false
let or: bool = a.or(b);     // true
let not: bool = a.not();    // false
let nand: bool = a.nand(b); // true (!(a && b))
let nor: bool = a.nor(b);   // false (!(a || b))
let xor: bool = a.xor(b);   // true (a != b)
```

#### Bitwise Operators

```rust
let a: u8 = 0b1100u8;  // 12 in decimal
let b: u8 = 0b1010u8;  // 10 in decimal

let and: u8 = a & b;           // 0b1000 (8 in decimal)
let or: u8 = a | b;            // 0b1110 (14 in decimal)
let xor: u8 = a ^ b;           // 0b0110 (6 in decimal)
let not: u8 = !a;              // 0b11110011 (243 in decimal)
let shl: u8 = a << 1u8;        // 0b11000 (24 in decimal)
let shr: u8 = a >> 1u8;        // 0b0110 (6 in decimal)
```

Method syntax:

```rust
let and: u8 = a.and(b);        // 0b1000 (8)
let or: u8 = a.or(b);          // 0b1110 (14)
let xor: u8 = a.xor(b);        // 0b0110 (6)
let not: u8 = a.not();         // 0b11110011 (243)
let shl: u8 = a.shl(1u8);      // 0b11000 (24)
let shr: u8 = a.shr(1u8);      // 0b0110 (6)
```

Wrapped versions are also available for shift operations:

```rust
let shl_wrapped: u8 = 128u8.shl_wrapped(1u8);   // 0 (wraps around)
let shr_wrapped: u8 = 1u8.shr_wrapped(1u8);     // 0
```

#### Other Mathematical Operators

```rust
// Remainder (uses truncated division rules)
let rem: u8 = 7u8 % 3u8;              // 1
let rem_method: u8 = 7u8.rem(3u8);    // 1

// Modulo (always follows mathematical definition of modulo)
let mod_value: u8 = 7u8.mod(3u8);     // 1 (same as rem for positive numbers)

// Absolute value
let abs_value: i8 = (-5i8).abs();     // 5i8

// Square
let square: field = 5field.square();  // 25field

// Square root
let sqrt: field = 25field.square_root(); // 5field
```

#### Ternary Operator

The ternary (conditional) operator allows for concise conditional expressions:

```rust
let condition: bool = true;
let value: u8 = condition ? 1u8 : 2u8;  // value = 1u8
```

#### Signature Verification

```rust
// Verify that a signature was created by a specific address for a specific message
let is_valid: bool = signature::verify(sig, signer_address, message);

// Method syntax
let also_valid: bool = sig.verify(signer_address, message);
```

### Special Operators and Constants

#### Group Generator

The `group::GEN` constant provides access to the generator point of the elliptic curve group:

```rust
let g: group = group::GEN;  // The group generator
```

#### Double Operation

The `double` method performs doubling operation on field and group elements:

```rust
let a: field = 3field;
let doubled_a: field = a.double();  // 6field

let p: group = 2group;
let doubled_p: group = p.double();  // Point doubling on the elliptic curve
```

#### Inverse Operations

The multiplicative inverse can be computed for field elements:

```rust
let a: field = 2field;
let a_inv: field = a.inv();  // 1/2 in the field
```

### Best Practices for Operators

When working with operators in Leo, keep these best practices in mind:

1. **Use checked operations by default** for better safety, unless you specifically need wrapping behavior.
2. **Be careful with type conversions** when working with different numeric types.
3. **Consider overflow/underflow risks** when performing operations near the bounds of a type's range.
4. **Use parentheses liberally** to make your code's precedence explicit, especially in complex expressions.
5. **Take advantage of method syntax** when it makes your code more readable.
6. **Be mindful of the differences between `rem` and `mod`** operations, especially when working with negative numbers.
7. **Use cryptographic operations appropriately** based on your security and performance requirements.

### Common Patterns and Examples

#### Safely Incrementing a Counter

```rust
// Safe increment with overflow checking
function increment(counter: u32) -> u32 {
    return counter + 1u32; // Will halt if counter is at maximum
}

// Wrapping increment for cases where overflow is acceptable
function wrapping_increment(counter: u32) -> u32 {
    return counter.add_wrapped(1u32); // Will wrap to 0 if counter is at maximum
}
```

#### Computing an Average

```rust
function average(a: u32, b: u32) -> u32 {
    // Avoid overflow by adding in a different order
    return a / 2u32 + b / 2u32 + (a % 2u32 + b % 2u32) / 2u32;
}
```

#### Checking Permissions

```rust
function has_permission(user: address, owner: address, admin: address) -> bool {
    return user == owner || user == admin;
}
```

#### Creating a Simple Hash-based Commitment

```leo
function create_commitment(value: u64, salt: scalar) -> field {
    return BHP256::hash_to_field((value, salt));
}
```

### Type-Specific Operator Behavior

Different types in Leo may have different behaviors with the same operators. Here's a quick summary:

#### Integer Types (i8, i16, i32, i64, i128, u8, u16, u32, u64, u128)

* Support full arithmetic operations
* Checked operations will halt on overflow/underflow
* Wrapping operations available for all arithmetic operations
* Support all bitwise operations

#### Field Type

* Supports addition, subtraction, multiplication, division, square, square\_root, inverse
* Does not support bitwise operations
* No overflow concerns (the field is very large)

#### Group Type

* Supports addition and scalar multiplication (for elliptic curve points)
* Supports negation and doubling
* Special operation: scalar multiplication with a scalar type

#### Boolean Type

* Supports logical operations: and, or, not, xor, nand, nor
* Can be used in ternary operations as the condition
