# MPC backups

This page describes how to back up a key-management system deployed using multi-party computation (MPC).

Ripple does its own backups for disaster recovery purposes. This page is for customers who want or require the ability to create their own backups to maintain in their own possession.

With multi-party computation (MPC), you cannot rely on single-instance keys, as both you and Ripple have only shards of the complete keys. So the challenge is to create a verifiable backup, in the sense that you can verify that all the key shards are valid in themselves and that they constitute the correct full keys.

Important:
You must execute the backup intents and API operations described on this page, from the *root domain*. If executed from a non-root domain, they return error code **400: Bad request**.

Also, only the backup creator can download the backup "trusted entity" payload.

## Background: Verifiable encryption

This section is for background only. You do not need to understand verifiable encryption to do MPC backups.

*Verifiable encryption* (VE) is an encryption scheme where one party (the *provider* or *prover*) encrypts a secret with a public key, where the corresponding private key (the decryption key) is held by another party, the *receiver*. The provider must prove to a third party, the *verifier*, that the encrypted text (the *ciphertext*) is the encryption of the secret, when neither the provider nor the verifier have the private (decryption) key. Because of the separation of the verifier from the decryption key, this lets you download and verify backups without the decryption key.

The concept of verifiable encryption was introduced in 1996 by [Markus Stadler](https://crypto.ethz.ch/publications/files/Stadle96.pdf), and later generalized for any public key encryption scheme. Verifiable encryption is an example of a *zero-knowledge proof* (*ZK proof*), where the verified knowledge is a secret which is encrypted by a public key scheme.

## Overview

This section is a short overview of the details provided below.

### The backup scripts

As you are onboarding MPC-based vaults, your Ripple liaison provides two scripts:

* The *backup key-generation script* — This script generates both an encryption key that you will provide to Ripple Custody for creating backups, and a decryption key that you store in your own KMS separate from Ripple.
* The *backup verification script* — This script lets you verify the validity of a backup that you have generated and downloaded in JSON form.


### Before you begin — Prerequisites

Before you begin, you need to have the following:

* A key-management system (KMS) to store the decryption key. This must be separate from Ripple's KMS.
* The *backup key-generation script* and the *backup verification script* provided to you by your Ripple liaison.
* Ability to execute intents and API operations from the *root domain*.


### Summary of the backup and verification steps

The steps, described in more detail below, are as follows:

1. Before registering an MPC vault with Ripple Custody, you execute the *backup key-generation script*, which generates one pair of RSA keys — the encryption (public) key and the decryption (private) key for the backup. The script stores the decryption key directly in a key-management system of your choice. You do not share this with Ripple.
2. You register the encryption key with Ripple Custody to associate it with the vault, either at the time you execute the `v0_CreateVault` intent, or at any other time by executing the `v0_UpdateVault` intent. Ripple can now use this encryption key to create the backup file when you request it.
3. To create a backup, submit the `v0_CreateBackup` intent to have Ripple Custody generate the downloadable backup.
4. You check the status of the backup request, using the **Get Backup information** API operation, to see when the backup is ready to download.
5. When the backup is ready, you call the **Get Backup trusted entity details** API operation to retrieve the backup as a JSON payload containing the encrypted shards.
6. You then acknowledge receipt of the backup, using the `v0_AcknowledgeBackup` intent, which blocks it from being downloaded again.
7. You can then run the *backup verification script* to verify the backup.


## Details

The following sections describe the MPC backup procedure in detail.

### Generate the backup encryption/decryption keys

Before registering an MPC vault with Ripple Custody, you must generate two RSA keys — the encryption (public) key, and the decryption (private) key for the backup.

To generate the encryption and decryption keys, run the *backup key-generation script* provided to you by your Ripple liaison.

When you run the script, you need to provide a link to the key-management system (KMS) you want to use to store the decryption key.

The *backup key-generation script* generates the following output:

* A public key that you will register with the Ripple Custody `v0_CreateVault` intent as the `backupEncryptionKey` parameter.
* A private key stored in the KMS you specified, and that is needed to decrypt the backups. This is not shared with Ripple.


Important
As the private key is not shared with Ripple — the script stores it directly in the key-management system (KMS) you have chosen, and which is outside of Ripple's control — your institution is responsible for the maintenance and security of the private (decryption) key. Ripple cannot be responsible for your private key if it is lost or compromised.

### Associate the encryption key with the vault

To create a backup for a vault created with MPC, the vault needs to have been created or updated with the `backupEncryptionKey` parameter set to the encryption key you generated with the *backup key-generation script*.

If you try to create a backup when this parameter is not set, this returns an `InvalidIntentError`:
"Creation of backup is not allowed for vault without backupEncryptionKey defined."

To attach the encryption key to the vault, specify the `parameters.backupEncryptionKey` field when proposing the `v0_CreateVault` intent to register the vault. If you have already created the vault, or want to change the encryption key, use the **UpdateVault** intent.

For more information, see [Register vaults](/products/custody/v1.34/api/environment/vault/register).

### Create the backup

To create a backup, make sure you are in the *root domain* and follow the steps in [Propose intents](/products/custody/v1.34/api/get-started/key-operations/update/intent-proposal), to submit a `v0_CreateBackup` intent for a specified vault, with a payload similar to the following example:


```json
{
  "data": {
      "id": "42bbd0e1-ce76-11eb-a921-dcfb48cfb3cb",
      "details": {
         "payload": {
            "id": "b7bh889a-ce76-11eb-a921-dcfb48cfb3cb",
            "parameters": {
              "vaultId": "0000000-0000-0000-0000-0000000001",
              "type": "VaultMpc"
            },
            "description": "Create MPC backup",
            "customProperties": {},
            "type": "v0_CreateBackup"
          }
      }
  }
}
```

This returns a payload similar to the following:


```json
{
  "items":[
    {
      "id": "...",
      "data": {
        "VaultBackupDataMpc": {
          "vaultId": "...",
          "acknowledged": false
        }
      },
      "metadata": {
        ...
      },
      "additionalDetails": {
        "processing": {
          "backupId": "a613341a-ce76-11eb-a921-dcfb48cfb3cb",
          "status": "Pending"
        }
      }
    }
  ]
}
```

The `processing` object contains both the `backupId` that you can use to request and download the full backup, and the `status` of the backup, which is initially set to `Pending`, and changes to `Completed` when the backup is ready for download.

### Check the status of the backup

To check the status of the generation of the backup JSON, call the **Get Backup information** API operation with the `backupId` returned from the `v0_CreateBackup` intent.


```
GET http://basename/v1/backups/a613341a-ce76-11eb-a921-dcfb48cfb3cb
```

This returns a payload similar to the following, and when the `status` has changed from `Pending` to `Completed`, the backup is ready to download.


```json
{
  "items":[
    {
      "id": "...",
      "data": {
        "VaultBackupDataMpc": {
          "vaultId": "...",
          "acknowledged": false
        }
      },
      "metadata": {
        ...
      },
      "additionalDetails": {
        "processing": {
          "backupId": "a613341a-ce76-11eb-a921-dcfb48cfb3cb",
          "status": "Completed"
        }
      }
    }
  ]
}
```

Alternatively, you can call the **List Backups** API operation with no parameters, and this will return a list of all requested backups.


```
GET http://basename/v1/backups/
```

### Download the backup

When the `status` of the backup request changes from `Pending` to `Completed`, the backup is ready to download.

Note:
Only the backup creator can download the backup "trusted entity" payload.

To download the generated backup JSON, call the **Get Backup trusted entity details** API operation with the `backupId`.


```
GET http://basename/v1/backups/a613341a-ce76-11eb-a921-dcfb48cfb3cb/trusted-entity
```

The returned JSON payload looks like the following:


```
{
  "data": {
    "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "data": {
      "type": "VaultMpc",
      "vaultId": "d3bde6fc-bf42-4298-8d0f-28928afd6780",
      "acknowledged": false,
      "backup": {
        "hash": "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
        "json": {
          "version": "1",
          "n.x": "0xed66c3566c1da7bfdff9913ad ...981887706645855738e6388a49043d",
          "e.x": "0x10001",
          "context": "0102030405060708",
          "keys": [
            {
              "curve": "secp256k1",
              "pubkey": "0x042989daf8b01fa84d7f7a1fa6a21ab23d99fe7a46dce46ae208499e68d5e05bb1c5e3f3b0637c91514421e3a08ef35bd94069da7202ed3be7b5c79f80c46de5f7",
              "shards": [
                {
                  "pubkey": "0x2c8a0ece195ad01d8a2593df53322e117986e570163b604d2e1870527c2bb91a7",
                  "curve": "secp256k1",
                  "rounds": [
                    {
                      "h": "9be1a78fc4163d491bec39cc821ddcde725c4c35de4b5eb7de26fde602a94cc",
                      "proof": {
                        "One": {
                          "alpha": "7e84b4093948517c42b97f08aab32572a0efa5a74ca3220236ed6ba",
                          "s": "1be081c6fe5a2cd9ee71e27742a659d77feb2e1e347fc4f53fc8ad0b6b7"
                        }
                      }
                    }
                  ]
                },
                {...},
                {...},
                {...}
              ]
            },
            {
              "curve": "secp256r1",
              "pubkey": "0x042989daf8b01fa84d7f7a1fa6a21ab23d99fe7a46dce46ae208499e68d5e05bb1c5e3f3b0637c91514421e3a08ef35bd94069da7202ed3be7b5c79f80c46de5f7",
              "shards": [
                {...},
                {...},
                {...},
                {...}
              ]
            },
            {
              "curve": "ed25519",
              "pubkey": "0x78ebd94d5c71b9dc38a1b67bd48302fb10ec8268ba87dc6c99afbe1f40be0d25",
              "shards": [
                {...},
                {...},
                {...},
                {...}
              ]
            }
          ],
        "derivationKeys": [
            {
              "curve": "secp256k1",
              "pubkey": "0x042989daf8b01fa84d7f7a1fa6a21ab23d99fe7a46dce46ae208499e68d5e05bb1c5e3f3b0637c91514421e3a08ef35bd94069da7202ed3be7b5c79f80c46de5f7",
              "shards": [
                {
                  "pubkey": "0x2c8a0ece195ad01d8a2593df53322e117986e570163b604d2e1870527c2bb91a7",
                  "curve": "secp256k1",
                  "rounds": [
                    {
                      "h": "9be1a78fc4163d491bec39cc821ddcde725c4c35de4b5eb7de26fde602a94cc",
                      "proof": {
                        "One": {
                          "alpha": "7e84b4093948517c42b97f08aab32572a0efa5a74ca3220236ed6ba",
                          "s": "1be081c6fe5a2cd9ee71e27742a659d77feb2e1e347fc4f53fc8ad0b6b7"
                        }
                      }
                    }
                  ]
                },
                {...},
                {...},
                {...}
              ]
            },
            {
              "curve": "secp256r1",
              "pubkey": "0x042989daf8b01fa84d7f7a1fa6a21ab23d99fe7a46dce46ae208499e68d5e05bb1c5e3f3b0637c91514421e3a08ef35bd94069da7202ed3be7b5c79f80c46de5f7",
              "shards": [
                {...},
                {...},
                {...},
                {...}
              ]
            },
            {
              "curve": "ed25519",
              "pubkey": "0x78ebd94d5c71b9dc38a1b67bd48302fb10ec8268ba87dc6c99afbe1f40be0d25",
              "shards": [
                {...},
                {...},
                {...},
                {...}
              ]
            }
          ]
        }
      }
    },
    "metadata": {
      "description": "string",
      "revision": 1,
      "createdAt": "2019-08-24T14:15:22Z",
      "createdBy": {
        "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
        "domainId": "8a0b02c3-fdd8-452e-bc6e-ef07a335ec7e"
      },
      "lastModifiedAt": "2019-08-24T14:15:22Z",
      "lastModifiedBy": {
        "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
        "domainId": "8a0b02c3-fdd8-452e-bc6e-ef07a335ec7e",
        "customProperties": {
          "property1": "string",
          "property2": "string"
        }
      }
    }
  },
  "signature": "OD3Yqiq22o2QZ9HxujMAlnsDgn8L+rEN95siRCVGfdzR2DRqVkhXM7m0Tl49Wbraa54cMVXxTjcohPhnucTg6g==",
  "additionalDetails": {
    "processing": {
      "status": "Completed"
    }
  }
}
```

Note:
The exact format of the JSON may change in the future. For the most updated information, see the **Get Backup trusted entity details** API reference page.

This JSON includes the following:

* All the root keys and derivation keys in encrypted form.
* Four shards for each key.
* Zero-knowledge proof data allowing verification without decryption.


The zero-knowledge proof data consists of the following:

* **version** — The version of the backup logic.
* **n.x** — The `backupEncryptionKey` that you generated using the encryption/decryption script and associated with the vault using the `v0_CreateVault` or `v0_UpdateVault` intent.
* **e.x** — The exponent part of the RSA key, hardcoded in the MPC context.
* **context** — The context for backup freshness provided by you as the `intentId` in the `v0_CreateBackup` intent.


The `keys` and `derivationKeys` arrays contain the following:

* **keys.curve** — The curve used for key generation.
* **keys.pubkey** — The full public key associated with the root key.
* **keys.shards** — Arrays of data corresponding to the four root key shards.
  * **keys.shards.curve** — The curve associated with the shard.
  * **keys.shards.rounds** — The 80 cut-and-choose verification rounds for the zero-knowledge proof.
* **derivationKeys.curve** — The curve used for derivation key generation.
* **derivationKeys.pubkey** — The full public key associated with the derivation key.
* **derivationKeys.shards** — Arrays of data corresponding to the four derivation key shards.
  * **derivationKeys.shards.curve** — The curve associated with the derivation key shard.
  * **derivationKeys.shards.rounds** — The 80 cut-and-choose verification rounds for the zero-knowledge proof.


### Acknowledge the backup

Once you have downloaded the generated MPC backup, you should acknowledge receipt of the backup by submitting the `v0_AcknowledgeBackup` intent. This is a security measure as it blocks the backup from being downloaded again using **Get Backup trusted entity details**.


```json
{
  "data": {
    "id": "42bbd0e1-ce76-11eb-a921-dcfb48cfb3cb",
    "details": {
      "payload": {
        "backupId": "00000000-0000-0000-0000-000000000001",
        "type": "v0_AcknowledgeBackup"
      }
    }
  }
}
```

### Verify the backup

To verify the validity of the backup JSON, run the *backup verification script*.

* Input: The downloaded backup JSON.
* Output: Either success or error.


## Exit strategy

This section is for risk/compliance stakeholders who require information on how to use a backup to recover the encrypted wallet keys, in the event of an exit from Ripple. This information is not required to create the backups as described above.

Many companies, for regulatory reasons, require an exit strategy to invoke in the case where the company is terminating its client relationship with Ripple, or in the case where Ripple itself experiences insolvency.

Ripple provides a third script — separate from the *backup key generation script*, and the *backup verification script* — for you to use in case of exit from Ripple Custody.  Unlike the other two scripts, the exit strategy script is placed in code escrow, to be accessed only in the case of Ripple insolvency.  Alternatively, if you terminate your client relationship with Ripple, it is part of Ripple's contract obligation to deliver the exit strategy script to you.

This script lets you recover the decrypted wallet keys for your wallet accounts.

The code for the script is based on the code for the second script, the backup verification script. In other words the verification script ensures that the exit strategy script will be able to decrypt the information in the verified JSON file.

The key recovery process involves three main steps:

1. Obtain the derivation information needed by the exit strategy script.
2. Format the derivation information as a JSON file.
3. Run the script to recover the wallet keys.


These are described in the following sections.

### Obtain the derivation information

To construct the derivation information file to feed to the exit strategy script, do the following:

Call the **Get account details** API operation.


```
GET http://basename/v1//domains/{domainId}/accounts/{accountId}
```

This returns the derivation path information for the account in the JSON response attributes.


```
{
  "data": {
[...]
    "providerDetails": {
      "vaultId": "00000000-0000-0000-0000-000000000000",
      "keyStrategy": "VaultHard",
      "keyInformation": {
        "publicKey": {
          "value": "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE8995OIBuo+OY2qDTy05U4dKoMCED8zE/h+HFmNHM7YuKPdnQdxaHpjFkFOD15G1fSlGAIsSH8jADx1MwKpu02g==",
          "chainCode": "xGWTHC5Je1ucPGNfWaBXiPFIVQpTgG5qiMkcFGTRxFQ=",
          "type": "ExtendedPublicKey"
        },
        "derivationPath": "1'/1'",
        "type": "VaultDerived"
      },
      "keys": [
        {
          "id": "ED25519_CUSTODY_1",
          "derivationPath": "1'/1'",
          "publicKey": {
            "value": "MCowBQYDK2VwAyEALafh+D4sRBPCoc8NOGA0DUs+heE+15GGaBPjBujwmjA=",
            "chainCode": "jO8tnGwyIVxH5qJosb2uYH2yXpQ+c0f0ZHYgWjXvEKo=",
            "type": "ExtendedPublicKey"
          },
          "type": "VaultDerived"
        },
[...]
        {
          "id": "SECP256K1_CUSTODY_1",
          "derivationPath": "1'/1'",
          "publicKey": {
            "value": "MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE8995OIBuo+OY2qDTy05U4dKoMCED8zE/h+HFmNHM7YuKPdnQdxaHpjFkFOD15G1fSlGAIsSH8jADx1MwKpu02g==",
            "chainCode": "xGWTHC5Je1ucPGNfWaBXiPFIVQpTgG5qiMkcFGTRxFQ=",
            "type": "ExtendedPublicKey"
          },
          "type": "VaultDerived"
        }
      ],
      "type": "Vault"
    },
[...]
```

Each account can have up to four keys, depending on ledger:

* `SECP256K1_CUSTODY_1` for Bitcoin, Ethereum, Tron, and XRPL.
* `ED25519_CUSTODY_1` for Tezos, Substrate, Stellar, Solana, Algorand, and Hedera.
* `ED25519_CUSTODY_2` for custody of assets on Cardano.
* `ED25519_STAKING_1` for staking of assets on Cardano.


From this you can derive the information you need to generate the derivation information JSON you need to feed into the MPC exit strategy script.

* The path in `data.providerDetails.keys[*].derivationPath`
* The public key in `data.providerDetails.keys[*].publicKey.value`
* The curve in `data.providerDetails.keys[*].id`.


For more information about derivation strategies and paths, see [Key derivation](/products/custody/v1.34/concepts/key-derivation).

### Format the derivation information as a JSON file

The resulting derivation information JSON file is as follows:


```
[
  {
    "path": "0'/0'",
    "publicKey": "string",
    "curve": "string" | null
    }
]
```

### Call the exit strategy script

The exit strategy script takes as input three files:

* The backup JSON file that you have generated and downloaded;
* The path to the decryption key that you generated with the *backup key generation* script;
* The file containing the JSON derivation information described above.


And it produces as output an array of account key objects corresponding to the derivation paths.


```
[
  {secret, publickey},
  {secret, publickey}
]
```

These are in clear text so you can use them to generate raw transaction signatures. The capability to format correct raw transactions for withdrawal operations in this context is the sole responsibility of the customer terminating its client relationship with Ripple.