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

# Layer 4 disaster recovery runbook

> Step-by-step procedure to recover private keys from Layer 4 backups using the dfns-signer-backup-restore tool, independently of DFNS.

export const SupportLink = ({children}) => {
  const url = "https://support.dfns.co";
  return <a href={url} target="_blank">{children || url}</a>;
};

Recover your private keys from [Layer 4](/advanced/deployment-models/disaster-recovery#layer-4-disaster-recovery) backups using the `dfns-signer-backup-restore` tool. The procedure is independent of DFNS: you need only your recovery private key and the encrypted backup files from your own S3 bucket.

Recovery follows an air-gapped model. Your recovery private key stays on an offline computer that never connects to a network. You download the encrypted shares on an online computer, carry them to the offline computer on removable media, and decrypt, assemble, and test the keys there. Only non-sensitive data crosses between the two: the encrypted shares coming in, and a signed transaction going out.

For how Layer 4 works and how to enable it, see the [disaster recovery overview](/advanced/deployment-models/disaster-recovery#layer-4-disaster-recovery) and the [Layer 4 setup steps](/advanced/deployment-models/mpc-runbook#set-up-layer-4-disaster-recovery-optional) in the MPC signer deployment runbook.

<Warning>
  The recovery private key, the decrypted shares, and the assembled private keys are highly sensitive. Keep them only on the offline computer and securely erase all key material — ideally wiping the computer — once recovery is complete.
</Warning>

## Recovery procedure

**Requirements:**

* An online computer with cloud CLI access (AWS, GCP, or Azure) to download the encrypted shares from your bucket.
* An offline computer to hold the recovery key and run all decryption, assembly, and signing. It must not connect to any network during recovery.
* A removable media (e.g. an SD card or a USB drive) to move files between the two computers.
* **On the offline computer:**
  * Your Layer 4 recovery private key in PEM format (this is the key you created when you configured the L4 backup).
  * the `dfns-signer-backup-restore` tool (contact our <SupportLink>Support Team</SupportLink> if you don't have access to it)

<Steps>
  <Step title="Download encrypted shares (online)">
    On the online computer, download all encrypted share files from your backup bucket. Each signer's shares are stored under its own prefix.

    <CodeGroup>
      ```bash AWS S3 theme={null}
      # Repeat for each signer prefix (signer-0, signer-1, ...)
      aws s3 cp s3://my-org-l4-backups/signer-0/ ./shares/signer-0/ --recursive
      aws s3 cp s3://my-org-l4-backups/signer-1/ ./shares/signer-1/ --recursive
      ```

      ```bash Google Cloud Storage theme={null}
      # Repeat for each signer prefix (signer-0, signer-1, ...)
      gcloud storage cp --recursive gs://my-org-l4-backups/signer-0/ ./shares/signer-0/
      gcloud storage cp --recursive gs://my-org-l4-backups/signer-1/ ./shares/signer-1/
      ```

      ```bash Azure Blob Storage theme={null}
      # Repeat for each signer prefix (signer-0, signer-1, ...)
      az storage blob download-batch \
        --account-name myorgl4backups --source backups \
        --pattern "signer-0/*" --destination ./shares/signer-0
      az storage blob download-batch \
        --account-name myorgl4backups --source backups \
        --pattern "signer-1/*" --destination ./shares/signer-1
      ```
    </CodeGroup>

    Copy the downloaded `shares` directory onto removable media. The shares are encrypted with your public key, so they are safe to handle on the online computer.
  </Step>

  <Step title="Decrypt the shares (offline)">
    Connect the removable media to the offline computer. Everything from here runs offline, alongside your recovery private key(s).

    Use the `dfns-signer-backup-restore` tool to decrypt the shares with your private key(s).

    ```bash theme={null}
    ./dfns-signer-backup-restore decrypt \
      --key-dir ./keys \
      --share-dir ./shares \
      --out-dir ./decrypted-shares
    ```

    | Parameter     | Description                                                    |
    | ------------- | -------------------------------------------------------------- |
    | `--key-dir`   | Directory containing your Layer 4 private key(s) in PEM format |
    | `--share-dir` | Directory containing the encrypted shares you copied over      |
    | `--out-dir`   | Output directory for the decrypted shares                      |
  </Step>

  <Step title="Assemble the private keys (offline)">
    Reconstruct the complete private keys from the decrypted shares.

    ```bash theme={null}
    ./dfns-signer-backup-restore assemble \
      --dir ./decrypted-shares \
      --out-dir ./recovered-keys
    ```

    | Parameter   | Description                                                      |
    | ----------- | ---------------------------------------------------------------- |
    | `--dir`     | Directory containing the decrypted shares from the previous step |
    | `--out-dir` | Output directory for the assembled private keys                  |

    The tool groups shares by their public key, reconstructs each private key, and verifies the result against that public key. You need at least the threshold number of shares per key (e.g. 3 out of 5 in a 3-of-5 scheme).
  </Step>
</Steps>

## \[Optional] Verify a recovered key

The assemble step already verified each recovered key against its public key, so the keys are cryptographically confirmed. For end-to-end confidence, you can additionally confirm a key signs by broadcasting a zero-value transaction on a testnet. Signing stays on the offline computer; only the signed transaction crosses to an online computer to broadcast — the private key never goes online.

<Warning>
  A recovered key is live and controls the same address on every chain. Test on a testnet (Sepolia) so no real assets move.
</Warning>

**Requirements:**

* Online computer to broadcast the signed test transaction.
* Offline computer to do the signature.
* Removable media (e.g. an SD card or a USB drive) to move files between the two computers.
* **On the online computer:**
  * Foundry's [`cast`](https://getfoundry.sh/cast/overview)
* **On the offline computer:**
  * Your Layer 4 recovery private key in PEM format (this is the key you created when you configured the L4 backup).
  * the `dfns-signer-backup-restore` tool (contact our <SupportLink>Support Team</SupportLink> if you don't have access to it)
  * `cast` (only used for [verification](#verify-a-recovered-key)), copy it over (see note below) from the online computer (if compatible) on a removable media rather than using a network installer.

<Note>
  ###### `cast` can be replaced by any other tool

  A bare shell cannot derive an address or sign an Ethereum transaction: it needs secp256k1, Keccak-256, and RLP encoding. That is why `cast` is requested on the offline computer. Address derivation and signing both run offline; only the broadcast needs connectivity.

  `cast` is a single self-contained binary so you just have to copy one file to the offline computer. Obtain it from a prebuilt binary on the online computer, download the [Foundry releases](https://github.com/foundry-rs/foundry/releases) matching the offline computer, verify its checksum, extract the `cast` binary, and copy it across.
</Note>

<Steps>
  <Step title="Collect transaction parameters (online)">
    On the online computer, note the values the offline signer needs: the address's current nonce, a gas price, and the chain ID (Sepolia is `11155111`). Fund the address with a little Sepolia test ETH from a public faucet — a zero-value transaction still needs gas. Carry these values to the offline computer.
  </Step>

  <Step title="Derive the address and sign (offline)">
    On the offline computer, read the `private_key` field from the assembled key file — for an Ethereum address, the one on the secp256k1 curve — and prefix it with `0x`.

    Derive the address and confirm it matches the one you funded:

    ```bash theme={null}
    cast wallet address --private-key 0x<private_key>
    ```

    Build and sign the transaction offline. This prints a signed raw transaction hex and broadcasts nothing:

    ```bash theme={null}
    cast mktx <address> \
      --value 0 \
      --nonce <nonce> \
      --gas-limit 21000 \
      --gas-price <gas_price> \
      --chain 11155111 \
      --legacy \
      --private-key 0x<private_key>
    ```

    Copy the signed raw transaction hex onto removable media. It contains no private key, so it is safe to move to an online computer.
  </Step>

  <Step title="Broadcast the signed transaction (online)">
    On the online computer, broadcast the signed transaction by pasting it into Etherscan's [Broadcast Transaction](https://sepolia.etherscan.io/pushTx) page, or from any machine with an RPC endpoint:

    ```bash theme={null}
    cast publish <signed_raw_tx> --rpc-url https://rpc.sepolia.org
    ```

    A returned transaction hash confirms the recovered key signs correctly.
  </Step>
</Steps>
