# Backup and Recovery

### 1. **Automatic Backups**

Backups are created automatically when accounts or settings are modified. These backups are **encrypted locally using ML-KEM before being uploaded** to a remote server.

#### Why ML-KEM?

* **NIST-standardized lattice-based algorithm** .
* Resistant to attacks from both classical and quantum computers.
* Used to securely encrypt sensitive data like account records and recovery information.

***

#### Encryption Flow: ML-KEM + XSalsa20-Poly1305

The wallet uses a **hybrid encryption model** :

1. A **shared secret** is generated using ML-KEM.
2. The actual data is encrypted using **XSalsa20-Poly1305** , a symmetric cipher.
3. The shared secret is then encapsulated using the recipient's **ML-KEM public key** .

```typescript
{
  "capsule": "0x...",          // ML-KEM ciphertext (encapsulated shared secret)
  "symmetricCiphertext": "0x...",  // XSalsa20-Poly1305 encrypted payload
  "nonce": "0x..."             // Random nonce used for symmetric encryption
}
```

```typescript
async encryptBackup(backupBuffer: Buffer, encryptionPublicKey: string): Promise<string> {
  const recipientPubKeyBuffer = hexToBuffer(encryptionPublicKey);

  // Step 1: Generate shared secret using ML-KEM encapsulation
  const { cipherText: capsule, sharedSecret } = ml_kem768.encapsulate(recipientPubKeyBuffer);

  // Step 2: Generate random nonce for symmetric encryption
  const nonce = crypto.randomBytes(24); // 24-byte nonce for XSalsa20

  // Step 3: Encrypt payload using XSalsa20-Poly1305
  const symmetricCiphertext = secretbox(backupBuffer, nonce, sharedSecret);

  // Step 4: Return structured JSON blob
  return JSON.stringify({
    capsule: bufferToHex(capsule),
    symmetricCiphertext: bufferToHex(symmetricCiphertext),
    nonce: bufferToHex(nonce),
  });
}
```

#### Uploading the Backup

After encryption, the backup is signed using **SLH-DSA** to ensure authenticity before upload.

```typescript
const signatureHex = await kr.sign(messageBuffer, {
  basePath: QL1evmNetworks.ql1evm.basePath,
  signerType: SignerType.slh_dsaevm,
  pathIndex: 0,
  walletType: WalletType.mnemonic,
});
```

The backup and signature are sent via an authenticated API call:

```typescript
await fetch(`${BACKUP_URL}backups/${account.publicKey}/users/${state.userId}`, {
  method: 'POST',
  headers: HEADERS,
  body: JSON.stringify({
    signature: signatureHex,
    payload: bufferToHex(Buffer.from(encryptedPayload)),
  }),
});
```

### 2. **Manual Recovery**

There are two main ways to restore a wallet:

***

#### Option A: **Recovery via Mnemonic Phrase (12/24 Words)**

**Process:**

1. User enters their **12/24-word mnemonic** during recovery.
2. The wallet regenerates:
   * **SLH-DSA signing keypair** (for Quranium Chain).
   * **ML-KEM encryption keypair** (for decrypting backups).
3. All accounts are re-created deterministically based on derivation paths.

```typescript
const entropy = Buffer.from(mnemonicToEntropy(mnemonic), "hex");
const seed96 = shake256.create({ dkLen: 96 }).update(entropy).digest();
const keys = slh.slh_dsa_shake_256f.keygen(seed96);
```

#### Option B: **Restore from Cloud Backup**

Use this option if you want to restore specific encrypted backups (e.g., saved settings or additional accounts).

**Requirements:**

* **ML-KEM Private Key** : Either regenerated from the mnemonic or exported earlier.
* **Encrypted Backup File** : Must contain the `capsule`, `symmetricCiphertext`, and `nonce`.

**Decryption Steps:**

1. Use the **ML-KEM private key** to extract the shared secret from the capsule.
2. Decrypt the symmetric ciphertext using the shared secret and nonce.

```typescript
async decryptBackup(encryptedMessageStr: string, encryptionKeypair: KeyPair): Promise<string> {
  const encryptedData = JSON.parse(encryptedMessageStr);
  const capsule = hexToBuffer(encryptedData.capsule);
  const symmetricCiphertext = hexToBuffer(encryptedData.symmetricCiphertext);
  const nonce = hexToBuffer(encryptedData.nonce);

  // Step 1: Decapsulate shared secret using ML-KEM
  const sharedSecret = ml_kem768.decapsulate(capsule, hexToBuffer(encryptionKeypair.privateKey));

  // Step 2: Decrypt symmetric data
  const decrypted = secretbox.open(symmetricCiphertext, nonce, sharedSecret);

  return bufferToHex(Buffer.from(decrypted));
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.qsafewallet.com/technical-details/backup-and-recovery.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
