> ## Documentation Index
> Fetch the complete documentation index at: https://docs.inco.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Operations

> Encrypted operations in the Inco Rust Crate

# Operations

The Inco Lightning SDK provides arithmetic, comparison, bitwise, and control flow operations on encrypted values.

## Arithmetic Operations

All arithmetic operations take a `CpiContext`, two operands, and a `scalar_byte` parameter. They return `Result<Euint128>`.

| Function | Description    | Signature                                                  |
| -------- | -------------- | ---------------------------------------------------------- |
| `e_add`  | Addition       | `(CpiContext, Euint128, Euint128, u8) -> Result<Euint128>` |
| `e_sub`  | Subtraction    | `(CpiContext, Euint128, Euint128, u8) -> Result<Euint128>` |
| `e_mul`  | Multiplication | `(CpiContext, Euint128, Euint128, u8) -> Result<Euint128>` |
| `e_rem`  | Remainder      | `(CpiContext, Euint128, Euint128, u8) -> Result<Euint128>` |

### Example: Encrypted addition with allowance

```rust theme={null}
use inco_lightning::cpi::accounts::{Operation, Allow};
use inco_lightning::cpi::{e_add, new_euint128, allow};

/// remaining_accounts:
///   [0] allowance_account (mut) - PDA for granting decrypt access
///   [1] owner_address (readonly) - The owner to grant access to
pub fn add_balances<'info>(
    ctx: Context<'_, '_, '_, 'info, AddBalances<'info>>,
    ciphertext_a: Vec<u8>,
    ciphertext_b: Vec<u8>,
) -> Result<()> {
    let cpi_program = ctx.accounts.inco_lightning_program.to_account_info();
    let signer = ctx.accounts.authority.to_account_info();

    // Convert ciphertexts to encrypted handles
    let cpi_ctx = CpiContext::new(cpi_program.clone(), Operation { signer: signer.clone() });
    let amount_a: Euint128 = new_euint128(cpi_ctx, ciphertext_a, 0)?;

    let cpi_ctx = CpiContext::new(cpi_program.clone(), Operation { signer: signer.clone() });
    let amount_b: Euint128 = new_euint128(cpi_ctx, ciphertext_b, 0)?;

    // Add two encrypted values
    let cpi_ctx = CpiContext::new(cpi_program.clone(), Operation { signer: signer.clone() });
    let result: Euint128 = e_add(cpi_ctx, amount_a, amount_b, 0)?;

    ctx.accounts.account.total = result;

    // Grant decryption access to owner via remaining_accounts
    if ctx.remaining_accounts.len() >= 2 {
        let allowance_account = &ctx.remaining_accounts[0];
        let allowed_address = &ctx.remaining_accounts[1];

        let cpi_ctx = CpiContext::new(
            cpi_program.clone(),
            Allow {
                allowance_account: allowance_account.clone(),
                signer: signer.clone(),
                allowed_address: allowed_address.clone(),
                system_program: ctx.accounts.system_program.to_account_info(),
            }
        );
        allow(cpi_ctx, result.0, true, ctx.accounts.account.owner)?;
    }

    Ok(())
}

#[derive(Accounts)]
pub struct AddBalances<'info> {
    #[account(mut)]
    pub authority: Signer<'info>,
    #[account(mut)]
    pub account: Account<'info, MyAccount>,
    /// CHECK: Inco Lightning program
    #[account(address = INCO_LIGHTNING_ID)]
    pub inco_lightning_program: AccountInfo<'info>,
    pub system_program: Program<'info, System>,
}
```

<Warning>
  Every operation that produces a new handle requires calling `allow()` to grant decryption access. Use the `remaining_accounts` pattern to pass allowance PDAs and grant access in the same transaction. See [Access Control](/svm/guide/access-control) for simulation patterns on the client side.
</Warning>

## Comparison Operations

Comparison operations return `Result<Ebool>`.

| Function | Description           | Signature                                               |
| -------- | --------------------- | ------------------------------------------------------- |
| `e_ge`   | Greater than or equal | `(CpiContext, Euint128, Euint128, u8) -> Result<Ebool>` |
| `e_gt`   | Greater than          | `(CpiContext, Euint128, Euint128, u8) -> Result<Ebool>` |
| `e_le`   | Less than or equal    | `(CpiContext, Euint128, Euint128, u8) -> Result<Ebool>` |
| `e_lt`   | Less than             | `(CpiContext, Euint128, Euint128, u8) -> Result<Ebool>` |
| `e_eq`   | Equal                 | `(CpiContext, Euint128, Euint128, u8) -> Result<Ebool>` |

## Bitwise Operations

| Function | Description | Signature                                                  |
| -------- | ----------- | ---------------------------------------------------------- |
| `e_and`  | Bitwise AND | `(CpiContext, Euint128, Euint128, u8) -> Result<Euint128>` |
| `e_or`   | Bitwise OR  | `(CpiContext, Euint128, Euint128, u8) -> Result<Euint128>` |
| `e_not`  | Bitwise NOT | `(CpiContext, Euint128, u8) -> Result<Euint128>`           |
| `e_shl`  | Shift left  | `(CpiContext, Euint128, Euint128, u8) -> Result<Euint128>` |
| `e_shr`  | Shift right | `(CpiContext, Euint128, Euint128, u8) -> Result<Euint128>` |

## Random Number Generation

| Function | Description                      | Signature                              |
| -------- | -------------------------------- | -------------------------------------- |
| `e_rand` | Generate encrypted random number | `(CpiContext, u8) -> Result<Euint128>` |

## Control Flow

### e\_select

Conditional selection on encrypted values without revealing the condition.

```rust theme={null}
e_select(ctx: CpiContext, condition: Ebool, if_true: Euint128, if_false: Euint128, scalar_byte: u8) -> Result<Euint128>
```

Returns `if_true` when condition is encrypted true, `if_false` otherwise.

### Example: Confidential transfer with balance check and allowance

```rust theme={null}
use inco_lightning::cpi::accounts::{Operation, Allow};
use inco_lightning::cpi::{e_add, e_sub, e_ge, e_select, as_euint128, allow};

/// remaining_accounts:
///   [0] source_allowance_account (mut)
///   [1] source_owner_address (readonly)
///   [2] dest_allowance_account (mut)
///   [3] dest_owner_address (readonly)
pub fn confidential_transfer<'info>(
    ctx: Context<'_, '_, '_, 'info, Transfer<'info>>,
    transfer_amount: Euint128,
) -> Result<()> {
    let inco = ctx.accounts.inco_lightning_program.to_account_info();
    let signer = ctx.accounts.authority.to_account_info();

    let source_balance = ctx.accounts.source.balance;
    let dest_balance = ctx.accounts.destination.balance;

    // Check if source has sufficient balance (encrypted comparison)
    let cpi_ctx = CpiContext::new(inco.clone(), Operation { signer: signer.clone() });
    let has_sufficient: Ebool = e_ge(cpi_ctx, source_balance, transfer_amount, 0)?;

    // Create zero for failed transfer case
    let cpi_ctx = CpiContext::new(inco.clone(), Operation { signer: signer.clone() });
    let zero = as_euint128(cpi_ctx, 0)?;

    // Select actual transfer amount: if sufficient balance, use amount; else use 0
    let cpi_ctx = CpiContext::new(inco.clone(), Operation { signer: signer.clone() });
    let actual_amount: Euint128 = e_select(cpi_ctx, has_sufficient, transfer_amount, zero, 0)?;

    // Subtract from source (will subtract 0 if insufficient)
    let cpi_ctx = CpiContext::new(inco.clone(), Operation { signer: signer.clone() });
    let new_source_balance: Euint128 = e_sub(cpi_ctx, source_balance, actual_amount, 0)?;

    // Add to destination (will add 0 if insufficient)
    let cpi_ctx = CpiContext::new(inco.clone(), Operation { signer: signer.clone() });
    let new_dest_balance: Euint128 = e_add(cpi_ctx, dest_balance, actual_amount, 0)?;

    // Update balances
    ctx.accounts.source.balance = new_source_balance;
    ctx.accounts.destination.balance = new_dest_balance;

    // Grant allowance to source owner for their new balance
    if ctx.remaining_accounts.len() >= 2 {
        let cpi_ctx = CpiContext::new(
            inco.clone(),
            Allow {
                allowance_account: ctx.remaining_accounts[0].clone(),
                signer: signer.clone(),
                allowed_address: ctx.remaining_accounts[1].clone(),
                system_program: ctx.accounts.system_program.to_account_info(),
            }
        );
        allow(cpi_ctx, new_source_balance.0, true, ctx.accounts.source.owner)?;
    }

    // Grant allowance to destination owner for their new balance
    if ctx.remaining_accounts.len() >= 4 {
        let cpi_ctx = CpiContext::new(
            inco.clone(),
            Allow {
                allowance_account: ctx.remaining_accounts[2].clone(),
                signer: signer.clone(),
                allowed_address: ctx.remaining_accounts[3].clone(),
                system_program: ctx.accounts.system_program.to_account_info(),
            }
        );
        allow(cpi_ctx, new_dest_balance.0, true, ctx.accounts.destination.owner)?;
    }

    Ok(())
}

#[derive(Accounts)]
pub struct Transfer<'info> {
    #[account(mut)]
    pub authority: Signer<'info>,
    #[account(mut)]
    pub source: Account<'info, TokenAccount>,
    #[account(mut)]
    pub destination: Account<'info, TokenAccount>,
    /// CHECK: Inco Lightning program
    #[account(address = INCO_LIGHTNING_ID)]
    pub inco_lightning_program: AccountInfo<'info>,
    pub system_program: Program<'info, System>,
}
```

<Note>
  This pattern ensures:

  * Balance check happens on encrypted values (no information leakage)
  * Transfer is atomic: either full amount transfers or nothing
  * No negative balances possible
  * Both source and destination owners can decrypt their new balances
</Note>

## Access Control Functions

Manage decryption permissions for handles.

| Function     | Description                                | Signature                                               |
| ------------ | ------------------------------------------ | ------------------------------------------------------- |
| `allow`      | Grant/revoke decryption access             | `(CpiContext<Allow>, u128, bool, Pubkey) -> Result<()>` |
| `is_allowed` | Check if address has decryption permission | `(CpiContext<IsAllowed>, u128) -> Result<bool>`         |

### allow

Grant or revoke decryption access for a specific address.

```rust theme={null}
pub fn grant_decrypt_access(
    ctx: Context<GrantAccess>,
    handle: u128,
    allowed_address: Pubkey,
) -> Result<()> {
    let cpi_ctx = CpiContext::new(
        ctx.accounts.inco_lightning_program.to_account_info(),
        Allow {
            allowance_account: ctx.accounts.allowance_account.to_account_info(),
            signer: ctx.accounts.authority.to_account_info(),
            allowed_address: ctx.accounts.allowed_address.to_account_info(),
            system_program: ctx.accounts.system_program.to_account_info(),
        },
    );

    allow(cpi_ctx, handle, true, allowed_address)?;
    Ok(())
}
```

### is\_allowed

Check if an address has decryption permission for a handle.

```rust theme={null}
pub fn check_access(
    ctx: Context<CheckAccess>,
    handle: u128,
) -> Result<bool> {
    let cpi_ctx = CpiContext::new(
        ctx.accounts.inco_lightning_program.to_account_info(),
        IsAllowed {
            allowance_account: ctx.accounts.allowance_account.to_account_info(),
            allowed_address: ctx.accounts.allowed_address.to_account_info(),
        },
    );

    is_allowed(cpi_ctx, handle)
}
```

## Attestation Verification

### is\_validsignature

Verify Ed25519 signatures for attested decryption results.

```rust theme={null}
is_validsignature(
    ctx: CpiContext<VerifySignature>,
    expected_signature_count: u8,
    handles: Option<Vec<Vec<u8>>>,
    plaintext_values: Option<Vec<Vec<u8>>>,
) -> Result<Vec<SignatureVerificationResult>>
```

#### Example

```rust theme={null}
pub fn verify_decryption(
    ctx: Context<VerifyDecryption>,
    handles: Vec<Vec<u8>>,
    plaintext_values: Vec<Vec<u8>>,
) -> Result<()> {
    let cpi_ctx = CpiContext::new(
        ctx.accounts.inco_lightning_program.to_account_info(),
        VerifySignature {
            instructions: ctx.accounts.instructions.to_account_info(),
            signer: ctx.accounts.authority.to_account_info(),
        },
    );

    // Verify Ed25519 signatures from previous instruction
    // The covalidator signs hash(handle + plaintext_value)
    let results = is_validsignature(
        cpi_ctx,
        1,                      // expected signature count
        Some(handles),          // handles being verified
        Some(plaintext_values), // claimed plaintext values
    )?;

    // If we get here, signatures are valid
    // Use the verified plaintext values
    Ok(())
}
```

<Note>
  The last parameter (`scalar_byte`) in operation calls identifies whether the left-hand side operand is ciphertext (`0`) or plaintext (`1`). Always pass `0` when working with encrypted handles.
</Note>
