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

# Precompiles

> Addresses, wire formats, and gas behavior for Metal precompiles

Metal extends the Ethereum Osaka precompile set with proof verification,
privacy primitives, Travel Rule verification, and Ed25519 verification. Contracts call these addresses with `STATICCALL`
or `CALL` using the binary inputs below.

## Address map

| Address | Precompile | Input summary | Output |
| - | - | - | - |
| `0xF2` | UltraHonk verifier | Verification key, proof, and public inputs | ABI boolean word |
| `0xF3` | BLAKE2s | Arbitrary bytes | 32-byte digest |
| `0xF4` | Poseidon2 hash | Count followed by field elements | One field element |
| `0xF5` | Poseidon2 permutation | Four field elements | Four field elements |
| `0xF6` | BN254 G2 scalar multiplication | G2 point and scalar | G2 point |
| `0xF7` | Grumpkin point addition | Two points | One point |
| `0xF8` | Grumpkin scalar multiplication | Point and scalar | One point |
| `0xF9` | Travel Rule verification | Commitments, digest, and co-signature | Recovered signing address or zero |
| `0xFB` | Ed25519 verification | Public key, signature, and message | ABI boolean word |

Related addresses:

| Address | Use |
| - | - |
| `0xF0` | [`CircuitRegistry`](https://docs.metalntwx.com/reference/privacy/circuit-registry) system contract |
| `0xF1` | Reserved |
| `0xFA` | Unassigned |
| `0xFC` | Read-only [Ethereum light-client protocol contract](https://docs.metalntwx.com/reference/interop/light-clients.md#ethereum-light-client); not a precompile |

The Osaka precompile at `0x100` provides RIP-7212 P-256 signature
verification, including WebAuthn use cases.

## Byte-order conventions

Unless a field says otherwise:

* fixed-width integers in custom wires are big-endian;
* field elements and curve coordinates occupy 32-byte words; and
* boolean results use the 32-byte ABI encoding of `0` or `1`.

Inputs must match the documented byte layout. A wrapper contract may expose an
ABI function that constructs this layout.

## UltraHonk verifier

Applications normally call `CircuitRegistry.verify(bytes)` at `0xF0`. The
registry resolves the verification key and constructs this `0xF2` input:

| Field | Size |
| - | -: |
| `circuitId` | 32 bytes |
| `keyLen` | 4 bytes |
| `backend` | 1 byte |
| `verificationKey` | `keyLen - 1` bytes |
| `proofLen` | 4 bytes |
| `proof` | `proofLen` bytes |
| `nPub` | 4 bytes |
| `publicInputs` | `nPub * 32` bytes |

```text theme={null}
circuitId
|| be32(keyLen)
|| backend
|| verificationKey
|| be32(proofLen)
|| proof
|| be32(nPub)
|| publicInputs
```

The supported backend tag is UltraHonk `0x02`. `keyLen` includes the backend
byte. The verifier requires
`keccak256(backend || verificationKey) == circuitId` and returns `1` for a
valid proof.

Base gas before Metal's CPU multiplier is:

```text theme={null}
400,000 + 16 * verificationKeyBytes + 5,000 * publicInputCount
```

## Hash and curve primitives

| Address | Wire | Base gas before multiplier | | | | | | | | |
| - | - | -: | - | - | - | - | - | - | - | - |
| `0xF3` | `message` | `400 + 12 * ceil(messageBytes / 64)` | | | | | | | | |
| `0xF4` | \`be32(inputCount) | | inputs\[inputCount]\` | `3,000 + 1,000 * inputCount` | | | | | | |
| `0xF5` | `state[4]` | `4,000` | | | | | | | | |
| `0xF6` | \`x0 | | x1 | | y0 | | y1 | | scalar\` | `30,000` |
| `0xF7` | \`x1 | | y1 | | x2 | | y2\` | `1,000` | | |
| `0xF8` | \`x | | y | | scalar\` | `10,000` | | | | |

`0xF3` returns the BLAKE2s-256 digest of the complete input.

For `0xF4`, each input and the result is one 32-byte field element. `0xF5`
accepts and returns exactly four such elements.

`0xF6` uses a BN254 G2 point encoded as four 32-byte coordinate limbs and
returns four limbs. Grumpkin points at `0xF7` and `0xF8` use `x || y` and
return the same 64-byte form.

## Travel Rule verification

`0xF9` verifies the Travel Rule record commitment and co-signature from a
virtual asset service provider (VASP). Its input is:

```text theme={null}
schemaVersion
|| ivmsRoot
|| be32(fieldCount)
|| fieldCommitments
|| expectedDigest
|| vaspSignature
```

| Field | Size | Requirement |
| - | -: | - |
| `schemaVersion` | 1 byte | Version `1` |
| `ivmsRoot` | 32 bytes | Canonical IVMS root |
| `fieldCount` | 4 bytes | Version 1 requires five fields |
| `fieldCommitments` | `fieldCount * 32` bytes | Ordered IVMS field commitments |
| `expectedDigest` | 32 bytes | Caller-supplied digest signed by the VASP |
| `vaspSignature` | 65 bytes | Recoverable VASP co-signature |

The output is the recovered VASP signing address left-padded to 32 bytes.
Invalid structure or signature returns 32 zero bytes. The calling policy
contract must construct and check the payment-bound digest and authorize the
recovered signer under its configured policy. The precompile does not inspect
payment semantics or legal completeness of the committed fields.

Base gas is `6,000 + 1,000 * fieldCount` before the CPU multiplier.

## Ed25519 verification

`0xFB` accepts:

```text theme={null}
publicKey[32] || signature[64] || message[remaining bytes]
```

It returns the 32-byte boolean encoding of the verification result. Base gas
is `4,000 + 12 * ceil(messageBytes / 64)` before the CPU multiplier.

## CPU gas multiplier

Metal multiplies the base gas of CPU-heavy precompiles by 64. This applies to
custom precompiles `0xF2` through `0xF9` and `0xFB`.

It also applies to these Osaka precompiles:

| Address | Standard precompile |
| - | - |
| `0x01` | `ECRECOVER` |
| `0x05` | Modular exponentiation |
| `0x06`–`0x08` | BN254 addition, multiplication, and pairing |
| `0x09` | BLAKE2f |
| `0x0A` | KZG point evaluation |
| `0x0B`–`0x11` | BLS12-381 operations and field-to-curve maps |
| `0x100` | P-256 signature verification |

SHA-256 at `0x02`, RIPEMD-160 at `0x03`, and identity at `0x04` retain their
standard Osaka pricing.

## Failure behavior

Every 32-byte field element passed to `0xF2` through `0xF8` must be
canonical: below the modulus of its field. The precompiles never reduce a
larger value. A non-canonical element is invalid input, so `0xF4` halts the
call and the others return the output in this table.

| Address | Invalid or malformed input |
| - | - |
| `0xF2` | Returns the 32-byte boolean encoding of `false` |
| `0xF3` | Returns 32 zero bytes |
| `0xF4` | Returns 32 zero bytes for malformed input; an internal hash failure halts the call |
| `0xF5` | Returns four zero words |
| `0xF6` | Returns a zero G2 point encoding |
| `0xF7`, `0xF8` | Returns a zero Grumpkin point encoding |
| `0xF9` | Returns a zero address padded to 32 bytes |
| `0xFB` | Returns the 32-byte boolean encoding of `false` |

An out-of-gas precompile call fails like any other EVM call. Wrapper contracts
must check the call status, output length, and returned value.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.