# Delegations

> Hashing, field and curve arithmetic have dedicated circuits. Which SDK calls reach them, what they cost, the rules on their operands, and the vendored crates that route library code to them.

Some computations are far cheaper to prove with a circuit built for them than as a stream of RISC-V instructions. Apogee calls these **delegations**. A delegation is a circuit family that proves one function of a frame of words in RAM, invoked by an `ecall`, and the guest SDK makes those calls for you behind ordinary functions. You never write an `ecall` yourself.

## What you call, and what it reaches

| You call | Delegation | One call proves |
| --- | --- | --- |
| `guest_sdk::keccak256(&[u8]) -> [u8; 32]` | `KECCAK_F` | one round of keccak-f[1600]; a permutation is 24 calls, and the sponge and padding are guest code |
| `guest_sdk::sha256(&[u8]) -> [u8; 32]` | `SHA256_COMP` | four rounds of the compression; a compression is 16 calls |
| `guest_sdk::ec_add`, `ec_mul`, `ec_identity` | `EC_ADD` | one third of a complete point addition on secp256k1 or BN254 G1 |
| `guest_sdk::poseidon2_permute(&mut [u8; 96])` | `POSEIDON2` | one width-3 Poseidon2 permutation over `Fr` |
| `field::Fr` addition, multiplication, inversion | `FR_ARITH` | one `Fr` operation, on the guest target, with nothing named |
| `transcript::poseidon2_permute` | `POSEIDON2` | the same permutation, through the transcript crate |
| `guest_sdk::recursion::mod_mul` over a `ModMulFrame` | `MOD_MUL` | one 256-bit `a·b mod m`, `m` one of four Ethereum moduli |

The functions are bit-identical to their software definitions. `keccak256` is Ethereum's Keccak, not SHA3-256. `sha256` is FIPS 180-4. `ec_add` uses the complete formula of Renes, Costello and Batina (2015, Algorithm 7), so doubling, `P + (−P)`, the identity and any `Z` need no special case.

```rust title="Hashing and curve arithmetic from a guest"
use guest_sdk::{ec_mul, keccak256, recursion::SECP256K1_GROUPS, ProjectivePoint};

let digest: [u8; 32] = keccak256(b"blockchain-native");

// A point is homogeneous projective (x = X/Z, y = Y/Z), each coordinate eight
// little-endian u32 limbs below the field modulus. The scalar is eight limbs too.
fn times(p: &ProjectivePoint, k: &[u32; 8]) -> ProjectivePoint {
    ec_mul(&SECP256K1_GROUPS, p, k).expect("EC_ADD is implemented on Apogee")
}
```

## Library code reaches them too

The guest workspace patches three crates so that the code inside them calls delegations on the guest target, with upstream's code as the fallback path:

| Crate | Version | Reaches |
| --- | --- | --- |
| `k256` | 0.13.4 | `MOD_MUL` from field and scalar multiplication; `EC_ADD` from `ProjectivePoint` addition, mixed addition and doubling |
| `ark-ff` | 0.6.0 | `MOD_MUL` from BN254's Montgomery multiply and square, in both of its fields |
| `revm-precompile` | 43.0.2 | `SHA256_COMP` for precompile `0x02`; `EC_ADD` for `0x06` and `0x07` |

A guest that depends on these crates gets the patched copies automatically through `guests/Cargo.toml`'s `[patch.crates-io]`. Unpatched, `k256`'s field multiply and square alone were 44% of a mainnet block's cycles. secp256k1 signature recovery is ordinary `k256` code, which the patches turn into delegated arithmetic.

## What a delegation costs

A delegation family is part of a program only if the program links one of its shims, and a call costs shards of that family's height:

- **Linked and never called: nothing.** The family is declared and proves zero shards.
- **Called once: a whole shard.** A shard costs its full height whatever its occupancy.
- **Called a lot: very little per call.** A shard's proof grows only by one sumcheck round per variable as its height grows.

| Family | Height | Unit of work | Calls per unit | Units per shard |
| --- | --- | --- | --- | --- |
| `KECCAK_F` | `2^18` | keccak-f[1600] | 24 | 10,922 |
| `SHA256_COMP` | `2^18` | one compression | 16 | 16,384 |
| `EC_ADD` | `2^16` | one complete addition | 3 | 21,845 |
| `MOD_MUL` | `2^16` | one `a·b mod m` | 1 | 65,536 |
| `POSEIDON2` | `2^8` | one permutation | 1 | 256 |
| `FR_ARITH` | `2^8` | one `Fr` operation | 1 | 256 |

The price is memory more than time: a `2^18` `KECCAK_F` shard's forward pass holds about 42 GiB of field elements, and two of them in flight set the measured Ethereum block's peak.

## Rules on operands

- **Operands below their modulus.** A `MOD_MUL` or `EC_ADD` operand at or above the modulus its selector names has no proof: the executor refuses the frame as a fatal `DelegationFrame`. The vendored `k256` reduces its lazily reduced field elements before calling.
- **Points are not checked for you.** `EC_ADD` proves the formula's arithmetic. Whether a point lies on the curve is the calling code's question, and a guest that takes points from advice must ask it.
- **Multi-call operations are one SDK function each.** A keccak permutation is 24 calls on one frame, a SHA-256 compression 16, a point addition 3. Each call proves its own step, and nothing refuses a wrong order: it computes something else. Use `keccak256`, `sha256` and `ec_add`, which issue the calls in order, rather than the raw shims.
- **Exit 72** means a delegation answered something its shim refuses. On Apogee's own executor this does not happen for a well-formed frame.

## What is not delegated

- The EVM's `MULMOD` with an arbitrary modulus, `MODEXP`, BLS12-381, and every primitive outside the table above run as instructions.
- No signature scheme or pairing is delegated as a whole. secp256k1 recovery is `k256` over `MOD_MUL` and `EC_ADD`; a BN254 pairing is `ark-bn254` over `MOD_MUL`.
- A delegation is an operation's core. Padding, sponges, block loops and a scalar multiplication's ladder are guest code, proved as instructions.

Signature schemes for guests are on the [v2.0.0 roadmap](https://apogee.gweb3networks.com/docs/quantum-leap/signatures).

## Is a new delegation worth it?

The cycle profiler prices the obvious candidates in every report, as a ceiling on the cycles a delegation could remove:

```text
removable = max(0, cycles − calls·(4 + 2·frame_words))
```

`cycles` is the category's share of the run, `calls` the entries into the candidate's functions, and `4 + 2·frame_words` the shim a delegation would leave behind: the frame's stores, the `ecall` and the result's loads. It charges nothing for the new family's shards, so treat it as an upper bound. [Run and profile](https://apogee.gweb3networks.com/docs/launch/run#profiler) shows a report.

The specification of each delegation, column by column, is under [Delegation circuits](https://apogee.gweb3networks.com/docs/auditors/spec/delegation-circuits).
