# Data integrity and governance

Executive summary
**Ripple Custody uses blockchain-inspired cryptographic structures to guarantee tamper-proof system state.**

- **Merkle tree** stores all trusted entities in a tamper-evident hash structure.
- **Anti-rewind file (ARF)** prevents replay attacks and state rollback.
- **Entity signatures** allow independent verification of any data item.
- Every state change is signed by the notary and timestamped.


Why this matters
Data integrity is essential for regulatory compliance and audit readiness. The cryptographic structures allow auditors to independently verify that no unauthorized changes have occurred. The anti-rewind protection ensures attackers cannot replay old transactions or roll back the system to a previous state.

**For architects and operators**: Understand the difference between *trusted* and *untrusted* components. The *notary* and *vault* are the only trusted components — everything else (including the database) is considered potentially compromised. This principle means a database breach cannot result in unauthorized transactions.

Prerequisites
Before reading this page, you should understand:

- [Security model](/products/custody/v1.36/overview/security-model) - The overall security model and zero-trust principles


## Overview

Trust in the state of the system is critical to integrity and auditing. The platform uses blockchain-inspired mechanisms to ensure data cannot be tampered with:

| Mechanism | Purpose |
|  --- | --- |
| **Merkle tree** | Tamper-evident data structure that detects any modification |
| **Anti-rewind file (ARF)** | Prevents replay attacks and state rollback |
| **Entity signing** | Each trusted entity has a cryptographic signature |


## Trusted vs. untrusted components

The platform is architecturally segregated to minimize the attack surface. From a data integrity perspective, only two components are trusted, the *notary* and the *vault*:

| Component | Trust Level | Data Integrity Role |
|  --- | --- | --- |
| **Notary** | Trusted | Signs the Merkle tree root after every state change. Maintains the ARF. All trusted entities must pass through the notary. |
| **Vault** | Trusted | Signs blockchain transactions. Verifies notary signatures before any key operation. |
| **All other components** | Untrusted | Cannot modify trusted data without detection. Database is treated as a key-value store; integrity is verified cryptographically, not assumed. |


This architecture means that even if an attacker compromises the database, API gateway, or any other untrusted component, they cannot forge trusted entities or execute unauthorized transactions.

For a complete list of all platform components and their functions, see [System architecture](/products/custody/v1.36/overview/architecture).

## Trusted vs untrusted entities

*Entities* are the data objects that make up the Ripple Custody environment. As with components, entities can be *trusted* or *untrusted*.

### Trusted entities

Trusted entities are protected by the data integrity model and signed by the notary:

| Entity | Description |
|  --- | --- |
| **Domains** | Organizational groupings for accounts |
| **Vaults** | Key management containers |
| **Ledgers** | Blockchain network configurations |
| **Accounts** | On-chain and virtual accounts |
| **Tickers** | Asset definitions |
| **Intents** | Signed requests to change state |
| **Endpoints** | Address book entries for approved blockchain destinations |
| **Policies** | Governance rules and approval flows |
| **Transaction orders** | Complex transaction instructions |
| **Users** | Human and machine identities |


### Untrusted entities

Untrusted entities are used or exposed without a signature. They must be protected with standard database security:

| Entity | Description |
|  --- | --- |
| **Fees** | Transaction fee calculations |
| **Addresses** | Blockchain addresses |
| **Balances** | Account balance snapshots |
| **Transactions** | On-chain transaction records |
| **Transfers** | Transfer execution records |
| **Requests** | API request logs |
| **Events** | System event logs |


## Merkle tree

A *Merkle tree* is a cryptographic data structure invented by Ralph Merkle in 1979 and now widely used in blockchain technology. The key insight is simple but powerful: by organizing data as a tree of hashes, you can detect any tampering instantly — if even a single byte changes anywhere in the data, the entire tree's "fingerprint" (the root hash) changes.

In Ripple Custody, the Merkle tree stores the cryptographic fingerprint of every trusted entity in the system. The notary signs the root hash after each state change. This means:

- **Auditors can verify history**: Given any historical root hash, you can prove exactly what the system state was at that moment.
- **Tampering is impossible to hide**: An attacker cannot modify the database without invalidating the signed root.
- **Verification is efficient**: To verify one entity, you only need to check its path to the root, not the entire database.


This is the same principle that makes blockchains tamper-evident, applied to the custody platform's internal state.

### How it works

The Merkle tree organizes all trusted entities into a hierarchical structure:

1. **Leaf nodes**: Each trusted entity (user, account, policy, etc.) is hashed to create a unique fingerprint.
2. **Parent nodes**: Each parent node contains the combined hash of its children.
3. **Root**: The single root hash represents the entire system state.


### Why this matters

| Benefit | Explanation |
|  --- | --- |
| **Tamper detection** | If any entity is modified, its hash changes, which changes all parent hashes up to the root. The signed root becomes invalid. |
| **Efficient verification** | To verify any single entity, you only need to check its path to the root—not the entire database. |
| **Cryptographic proof** | Third parties can independently verify that data was notarized by Ripple Custody at a specific point in time. |


Only the notary can update the Merkle tree. After each state change, it computes the new root and signs it, making any unauthorized modification immediately detectable.

## Anti-rewind file (ARF)

The *anti-rewind file* (*ARF*) keeps track of the most up-to-date Ripple Custody state version. This tracking is protected by cryptographic signatures, and is tamper-proof.

### What attacks does the ARF prevent?

The ARF protects against ****replay attacks**** & mdash; attempts by an attacker to:

| Attack | Description |
|  --- | --- |
| **Revert the system** | Restore an old database backup to "undo" transactions (e.g., reverse a withdrawal) |
| **Resubmit intents** | Replay a previously executed transfer to double-spend funds |
| **Forge state** | Present a manipulated database as authentic |


When an *intent* is submitted, the notary:

1. Compares the database state version against the ARF version
2. Verifies the Merkle tree root signature matches
3. Confirms the intent has not been previously executed


If any check fails, the intent is rejected.

### What happens if the ARF is lost?

If the ARF is lost, corrupted, or inaccessible, the notary immediately halts all write operations. This is a security feature, not a bug — it prevents the system from operating without its anti-rewind protection.

### How is the ARF recovered?

Recovery requires a formal, audited process involving a designated **State Review Authority**:

1. **Database verification**: The State Review Authority uses a secure, offline tool to export and validate all collections from a database backup.
2. **Integrity check**: The tool computes the Merkle tree root hash and verifies it matches the signed state.
3. **Manifest generation**: If valid, a signed manifest is generated attesting to the database's integrity.
4. **Recovery mode**: The notary restarts in recovery mode, processes the signed manifest, and rebuilds the ARF.
5. **Normal operation**: Once the ARF is rebuilt and verified, normal operations resume.


This process ensures that even in a disaster scenario, the system cannot be tricked into accepting a tampered database.

For detailed recovery procedures, see [Recover the anti-rewind file](/products/custody/v1.36/operations-and-maintenance/backup-and-restore/recover-anti-rewind-file).

## System update flow

Updates to the system state follow this process:

![System update flow](/assets/system-update-flow.6fdd412eb22f5a155654be4b8c71b209a7e3da405a304bc3e3a9037809a99e4d.695a62e7.png)

| Step | Description |
|  --- | --- |
| **Merkle tree validation** | The state is extracted from the database and shared with the notary alongside the intent. The notary verifies the Merkle tree version, validates the root signature, checks correspondence to state data, and verifies the user signature. |
| **State mutation** | The state is updated by adding or updating entities in the request. |
| **Merkle-proofed generation** | The Merkle tree is updated with the hash of the mutated entity. Its new root is signed by the notary, which also updates its local state in the ARF. |
| **Entity signature** | Each new entity is atomically signed for consistency. Third-party integrators can verify data was notarized by Ripple Custody. |


## Verifying custody signatures

All data payloads retrieved from Ripple Custody that are part of the secure data include a cryptographic signature. You can verify these signatures to confirm the data's authenticity and integrity.

### Why verify signatures?

Signature verification ensures:

- The data was genuinely produced by Ripple Custody
- The data has not been modified since it was signed
- You can independently audit the integrity of historical data


### How to verify a signature

1. **Retrieve the Ripple Custody public key** using the [Get system properties](/products/custody/v1.36/reference/api/openapi/systemproperties/getsystemproperties) API operation. The response includes the platform's public key:



```json
{
    "id": "CUSTODY_API_KEY",
    "value": {
        "publicKey": {
            "value": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1WXjDbBcWEVmqObzEndfnug+nd4EOEqcXMY5a5I0XvfRq1+K6Z9K1DdZ2YgFIbuzdX2Z2kOfE/fcDj/QzF5IAw==",
            "type": "PublicKey"
        }
    }
}
```

1. **Save the public key** to a file with PEM headers:



```
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1WXjDbBcWEVmqObzEndfnug+nd4EOEqcXMY5a5I0XvfRq1+K6Z9K1DdZ2YgFIbuzdX2Z2kOfE/fcDj/QzF5IAw==
-----END PUBLIC KEY-----
```

1. **Canonicalize the data object**. The signature was computed from canonical JSON, so you must recreate the same format:



```sh
cat data.json | jq -j -S -c > sorted_object.json
```

**jq flags explained:**

- `-S` — Sort object keys alphabetically
- `-c` — Compact output (removes all whitespace)
- `-j` — No trailing newline (critical for matching the original hash)


For full canonicalization rules including null removal and array handling, see [Canonicalization rules](/products/custody/v1.36/identity-and-access/authentication/authenticate-api-requests#canonicalization-rules).

The `-j` flag is essential. Without it, `jq` adds a trailing newline that becomes part of the hashed content, causing verification to fail.

1. **Convert the signature** from Base64 to binary:



```sh
openssl enc -d -A -base64 -in signature.txt -out signature.bin
```

1. **Verify the signature**:



```sh
openssl pkeyutl -verify -pubin -inkey CustodyPublicKey.pem -rawin -in sorted_object.json -sigfile signature.bin
```

If valid, the output is: `Signature Verified Successfully`

## Glossary

| Term | Definition |
|  --- | --- |
| **ARF** | Anti-rewind file. A cryptographically protected file stored by the notary that tracks the current state version to prevent replay attacks and database rollback. |
| **Confidential computing enclave** | A hardware-protected execution environment (such as IBM HPVS) where code and data are isolated from the host system, even from administrators. |
| **Hash** | A fixed-size cryptographic fingerprint of data. Any change to the input data produces a completely different hash, making tampering detectable. |
| **Merkle tree** | A tree-structured data organization where each node contains the hash of its children. Enables efficient verification that any piece of data is unmodified. |
| **Notarization** | The process of cryptographically signing data to attest to its authenticity and timestamp. In Ripple Custody, the *notary* notarizes all trusted entities. |
| **Replay attack** | An attack where a valid transaction or request is maliciously repeated. The ARF prevents this by tracking which intents have already been executed. |
| **Root hash** | The single hash at the top of a Merkle tree that represents the entire dataset. If any data changes, the root hash changes. |
| **State Review Authority** | A designated role responsible for verifying database integrity during ARF recovery. This person signs a manifest attesting that the database state is valid. |
| **Trusted entity** | A data object (user, account, policy, etc.) that is protected by the Merkle tree and signed by the notary. Tampering with trusted entities is cryptographically detectable. |
| **Untrusted entity** | A data object (fee, balance, event, etc.) that is not signed by the notary. These require standard database security measures. |
| **Zeroization** | The secure erasure of cryptographic keys, typically triggered automatically when tampering is detected in an HSM. |