# ML-KEM Encryption for Backups

<mark style="color:red;">**Backup Encryption Workflow (ML-KEM)**</mark>

#### **Step 1: Data Preparation**

* **Input**: Wallet data (accounts, keys, metadata) is serialized into a JSON string.
* **Hashing**: A SHA-256 hash of the JSON string is generated for integrity checks.
* **Serialization**: Data is converted to a **`Buffer`** for encryption.

#### **Step 2: ML-KEM Encryption**

* **Key Encapsulation**:
  * The recipient’s **ML-KEM public key** (stored in **`account.encryptionPublicKey`**) generates a shared secret.
  * ML-KEM’s **`encapsulate()`** function creates:
    * **Ciphertext**: Encapsulated shared secret (sent to the server).
    * **Shared Secret**: Used for symmetric encryption.
* **Symmetric Encryption**:
  * The shared secret encrypts the backup data using **XSalsa20** (or **AES-256**) for efficiency.
  * Result: A hybrid ciphertext (**`encryptedPayload`**) containing both ML-KEM ciphertext and symmetrically encrypted data.

#### **Step 3: Signature Generation (SLH-DSA)**

* **Hashing the Payload**:
  * The encrypted payload is hashed using Keccak-256 to create a fixed-size digest.
* **SLH-DSA Signing**:
  * The hash is signed using the user’s **SLH-DSA private key** (derived from their mnemonic).
  * Produces a **49,856-byte signature** for tamper-proof verification.

#### **Step 4: Cloud Storage**

* **Payload Structure**:

  ```json
  {
    "signature": "0x...", // 49,856-byte SLH-DSA signature
    "payload": "0x..."    // ML-KEM ciphertext + symmetrically encrypted data
  }
  ```
* **Server-Side Handling**:

  * Backups are stored under the user’s public key (**`account.publicKey`**).
  * The server uses SHA-256 to hash the public key for secure storage.

<mark style="color:red;">**Backup Verification:**</mark>

The server performs **security checks** before allowing access:

#### **Check 1: SLH-DSA Signature Validation**

* **Message Reconstruction**:
  * The server generates valid messages based on timestamps (e.g., **`pubkey-GET-BACKUPS-2023-09-01`**).

```tsx
const legitMessages = [  
  `${pubkey}-GET-BACKUPS-${ymdnow}`,  
  `${pubkey}-GET-BACKUPS-${ymdlb}`, // Lower bound timestamp  
  `${pubkey}-GET-BACKUPS-${ymdub}`, // Upper bound timestamp  
];  
```

* **Signature Verification**:

  * The server uses the user’s **SLH-DSA public key** to verify the signature against all possible messages.
  * Ensures the request is recent and untampered.

  ```tsx
  const valid = slh.slh_dsa_shake_256f.verify(  
    pubkeyBytes,  
    messageBuffer,  
    signature  
  );  
  ```

#### **Check 2: Ownership Proof**

* Ownership is verified through SLH-DSA signature. Since ML-KEM and SLH-DSA keys are derived from the same mnemonic, validating SLH-DSA signatures proves control over the ML-KEM private key.

```typescript
// Verify SLH-DSA signature to prove ownership of ML-KEM key
let provenOwnership = false;
for (const message of legitMessages) {
  const valid = slh.slh_dsa_shake_256f.verify(
    pubkeyBytes, // SLH-DSA public key (derived from same mnemonic as ML-KEM key)
    Buffer.from(message, "utf8"),
    byteStringToBytes(signature)
  );
  if (valid) {
    provenOwnership = true;
    break;
  }
}
if (!provenOwnership) {
  throw new HttpError(HttpStatus.BadRequest, ERROR_MESSAGE.INVALID_SIGNATURE);
}
```

<mark style="color:red;">**Backup Retrieval & Decryption**</mark>

#### **Step 1: Fetching the Backup**

* Users request backups via their public key and a timestamped signature.

  ```tsx
  const backup = await getBackup(userId);
  ```

#### **Step 2: ML-KEM Decryption**

* **Key Decapsulation**:

  * The user’s **ML-KEM private key** decrypts the ciphertext to recover the shared secret.

  ```tsx
  const sharedSecret = ml_kem.decapsulate(ciphertext, privateKey);
  ```
* **Symmetric Decryption**:
  * The shared secret decrypts the symmetrically encrypted data.

#### **Step 3: Data Reconstruction**

* The decrypted **`Buffer`** is parsed back into JSON.
* Accounts are reinitialized in the wallet.

  ```tsx
  const decryptedBackup: BackupData = JSON.parse(decryptedData.toString());
  ```
