> ## 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.

# IVMS Evidence

> The standalone Travel Rule precompile format and the private record committed in a MIP410 payment payload

Metal supports two formats for committing identity information: the standalone
Travel Rule precompile's five-field structural root, and MIP410's private payment
payload. They use different hashes and schemas. MIP410 does not call the
standalone precompile.

> [!NOTE]
>
> This is the Metal evidence profile for IVMS data. It does not replace the
> complete IVMS101 data model, encrypted record exchange, retention policy, or
> legal validation performed by the responsible virtual asset service providers (VASPs).

## Standalone precompile fields

The Travel Rule precompile at `0xF9` accepts these fields in packed binary form:

| Field | Encoding and meaning | | | | |
| - | - | - | - | - | - |
| `schemaVersion` | One byte selecting the field count and order | | | | |
| `ivmsRoot` | 32-byte field-reduced root of the ordered commitments | | | | |
| Field count | Four-byte big-endian count | | | | |
| `fieldCommitments` | That many 32-byte commitments in schema order | | | | |
| `expectedDigest` | 32-byte digest supplied by the calling policy | | | | |
| `vaspSig` | 65-byte secp256k1 signature over that digest, encoded as \`r | | s | | v\` |

A successful call returns the recovered signer as a left-padded 32-byte EVM
address. Malformed input, a structural mismatch, or an invalid signature returns
the zero address. The precompile does not check a registry or credential proof.
The caller must reconstruct the digest from the payment and IVMS root, compare
the recovered address with an authorized signer, and apply its expiry and replay
rules. It must not trust a digest supplied unchanged by the transaction sender.

## Schema version 1

Schema `1` requires exactly five commitments:

| Index | Field |
| - | - |
| `0` | Originator name |
| `1` | Originator account |
| `2` | Beneficiary name |
| `3` | Beneficiary account |
| `4` | One originator identifier |

The IVMS verifier treats each entry as an opaque `bytes32` commitment.
Raw values remain offchain. The precompile checks the count and root; it does
not open the commitments or require their values to be nonzero. A policy proof
that inspects a field must agree with the record producer on its encoding and
commitment scheme.

## IVMS root

The root is an ordered packed hash reduced into the BN254 scalar field:

```solidity theme={null}
uint256 constant FIELD_MODULUS =
    0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001;

ivmsRoot = bytes32(
    uint256(
        keccak256(
            abi.encodePacked(uint8(1), fieldCommitments)
        )
    ) % FIELD_MODULUS
);
```

Changing the schema version, field count, field order, or any commitment changes
the root. Schema `1` with any count other than five is malformed.

## MIP410 payload commitment

MIP410 commits an optional private record together with the payment and its
identifiers. The code uses `Fi` for the VASP role in identifiers such as
`recipientFiBindingCommitment`.

### Field commitments

Every field is committed under its own salt, derived from a per-payment seed:

```text theme={null}
salt_f = Poseidon2(DOMAIN_PAYLOAD_SALT, seed, f)
C(f)   = Poseidon2(DOMAIN_PAYLOAD_FIELD, f, salt_f, limbs_f...)
```

`f` is the field's index in the table below. Text is UTF-8 packed into 31-byte
limbs from the start, and each field has a fixed limb count; over-length text
is rejected rather than truncated. A field is absent exactly when all its limbs
are zero, so presence needs no flag. For the same reason, text cannot contain a
NUL byte, and the party type encodes a natural person as `1` and a legal person
as `2`.

### Payload schema version 1

The payload commits 28 fields: eleven per party, then the two VASPs, then four
ISO 20022 payment identifiers. Party fields list the originator's index first
and the beneficiary's second. In the IVMS101 column they belong to the party's
`originatorPersons` or `beneficiaryPersons` entry. In the ISO 20022 column,
`P` stands for `Dbtr` (originator) or `Cdtr` (beneficiary).

| Index | Field | Limbs | IVMS101 | ISO 20022 `pacs.008` |
| - | - | - | - | - |
| `0` / `11` | Name | 5 | `naturalPerson.name` or `legalPerson.name` | `P/Nm` |
| `1` / `12` | Account | 2 | `accountNumber[0]` | `PAcct/Id` |
| `2` / `13` | Address | 7 | `geographicAddress[0]` | `P/PstlAdr` |
| `3` / `14` | Country | 1 | `geographicAddress[0].country` | `P/PstlAdr/Ctry` |
| `4` / `15` | Legal identifier | 1 | `legalPerson.nationalIdentification` (type `LEIX`) | `P/Id/OrgId/LEI` |
| `5` / `16` | Party type | 1 | `naturalPerson` or `legalPerson` | `P/Id/PrvtId` or `P/Id/OrgId` |
| `6` / `17` | Date of birth | 1 | `naturalPerson.dateAndPlaceOfBirth.dateOfBirth` | `P/Id/PrvtId/DtAndPlcOfBirth/BirthDt` |
| `7` / `18` | Place of birth | 3 | `naturalPerson.dateAndPlaceOfBirth.placeOfBirth` | `P/Id/PrvtId/DtAndPlcOfBirth/CityOfBirth`, `CtryOfBirth` |
| `8` / `19` | Customer identification | 2 | `naturalPerson.customerIdentification` or `legalPerson.customerNumber` | `P/Id/PrvtId/Othr/Id` (scheme `CUST`) |
| `9` / `20` | National identifier | 2 | `nationalIdentification.nationalIdentifier` | `P/Id/PrvtId/Othr/Id` or `P/Id/OrgId/Othr/Id` |
| `10` / `21` | National identifier type and issuing country | 1 | `nationalIdentification.nationalIdentifierType`, `countryOfIssue` | `Othr/SchmeNm/Cd`, `Othr/Issr` |
| `22` | Originating VASP (LEI or BIC) | 1 | `originatingVASP` | `DbtrAgt/FinInstnId/LEI` or `BICFI` |
| `23` | Beneficiary VASP (LEI or BIC) | 1 | `beneficiaryVASP` | `CdtrAgt/FinInstnId/LEI` or `BICFI` |
| `24` | UETR | 1 | None | `PmtId/UETR` |
| `25` | End-to-end identifier | 2 | None | `PmtId/EndToEndId` |
| `26` | Remittance information | 5 | None | `RmtInf/Ustrd` |
| `27` | Purpose code | 1 | None | `Purp/Cd` |

Fields `0` to `23` form the travel-rule record. Fields `24` to `27` form the
payment identifiers.

### The tree

```text theme={null}
originatorLeaf  = Poseidon2(DOMAIN_PAYLOAD_PARTY, C(0) ... C(10))
beneficiaryLeaf = Poseidon2(DOMAIN_PAYLOAD_PARTY, C(11) ... C(21))
vaspLeaf        = Poseidon2(DOMAIN_PAYLOAD_VASP, C(22), C(23))
recordRoot      = 0, if every limb in fields 0–23 is zero
                  otherwise Poseidon2(DOMAIN_PAYLOAD_RECORD, 1,
                                      originatorLeaf, beneficiaryLeaf, vaspLeaf)
idsLeaf         = Poseidon2(DOMAIN_PAYLOAD_IDS, 1, C(24), C(25), C(26), C(27))
paymentLeaf     = Poseidon2(DOMAIN_PAYLOAD_PAYMENT, paymentEffectHash,
                            recipientFiBindingCommitment, nonce, deadline)
evidenceLeaf    = 0
commitment      = Poseidon2(DOMAIN_PAYLOAD_V1, paymentLeaf, idsLeaf,
                            recordRoot, evidenceLeaf)
```

The `1` in `recordRoot` is the record schema version, and the `1` in `idsLeaf`
is the payment identifiers profile version. A payload under any other version
fails to open. `recordRoot` is zero when no record accompanies the payment,
that is, when every record limb is zero. The evidence leaf is fixed to zero.
The current format carries no credential or screening-attester evidence in
that slot.

### Where the commitment is checked

The initiation proof recomputes the commitment from the payload plaintext,
taking the payment leaf from its own public inputs, and exposes the commitment
as a public input. The pool rejects a zero commitment and stores the
commitment on the hold. It supplies the stored value to the resolution proof
and the recipient VASP's wrapped policy proof. Reclaim uses the hold's deadline and requires no proof.

The plaintext travels offchain in two sealed halves. The memo is sealed to the
recipient's shielded address and carries the note opening, the payment effect,
the nonce, and the deadline, with the payload commitment in its cleartext
header. The 2230-byte institutional artifact is sealed to the recipient VASP's
registered messaging key by ECDH with that key. It carries the payload seed,
the payment identifiers, the travel-rule record, the sender VASP's identifier,
and the sender VASP's Schnorr signature by its messaging key over
`Poseidon2(DOMAIN_PAYLOAD_AUTH, commitment)`.

To authenticate a received payload, the recipient VASP assembles its two halves
against the onchain hold. It refuses the payment's content when the
memo disagrees with the hold, when the payload does not hash to the hold's
commitment, when the sender VASP is absent from the pool's institution registry,
or when its signature fails. The signature authenticates the signer, never the
truth of the record's values.

### Reading fields in a policy

A policy reads only the fields it screens. It checks the payload's four leaves
against the commitment, binds the record or identifier commitments to their
leaf, and opens each field it needs with that field's salt and limbs. Fields it
does not open stay hidden inside the proof. A policy binds the record only when
the record root is nonzero.

For example, the reference threshold policy requires a nonzero record root
before it permits `Accept` for a `*USDZ` payment of 50 `*USDZ` or more. It checks
record presence without opening individual fields. It places no record condition
on `Reject`, which stays the VASP's decision. A rejection can therefore proceed
without the institutional artifact, provided the recipient has the payment
opening needed for resolution. The wrapper still requires the VASP's
authorization of either outcome.

> [!NOTE]
>
> No X.509 VASP credential proof, screening-attester verdict, or in-circuit
> record signature is part of a MIP410 proof. The evidence leaf is reserved for
> them.

## Delivery acknowledgements

MIP410 has no built-in record-delivery acknowledgement format or receipt check.
A VASP can require delivery evidence through a custom policy, which must bind
that evidence to the payment. Accepting a payment does not by itself prove that
the record was decrypted or retained.

## Privacy and trust boundary

The standalone precompile checks the five-field structure and recovers a signer.
MIP410 verifies the payload commitment and the configured private policy, with
a separate VASP authorization in the wrapper. The chain receives no complete
IVMS record and does not establish that a committed identity value is accurate.

The sender and recipient VASPs remain responsible for:

* validating and retaining the IVMS101 record;
* selecting a lawful encrypted transport;
* confirming that the committed values match the exchanged record; and
* applying the rules required by their jurisdiction and operating model.

> [card] [Payment messaging](https://docs.metalntwx.com/learn/compliance/messaging.md)
>
> How institutions exchange payment instructions and Travel Rule records.

> [card] [Roles and authorization](https://docs.metalntwx.com/learn/mip410/roles-and-authorization.md)
>
> See how wallet and institution keys authorize MIP410 payments.

> [card] [Signing and EIP-712](https://docs.metalntwx.com/reference/network-fundamentals/signing.md)
>
> Look up the Metal typed-data domains and digest rules.

> [card] [MIP410 API](https://docs.metalntwx.com/reference/assets-and-payments/mip410.md)
>
> Look up MIP410 structs, entrypoints, and policy controls.


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