Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"editor.quickSuggestions": {
"strings": false,
"other": false,
"comments": false
},
}
8 changes: 8 additions & 0 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,20 @@
"tab": "World App",
"pages": [
"world-app/index",
"world-app/bedrock",
{
"group": "Backup & Recovery",
"pages": [
"world-app/backup/index",
"world-app/backup/structure-and-sync",
"world-app/backup/advanced"
]
},
{
"group": "Advanced",
"pages": [
"world-app/cryptography"
]
}
]
},
Expand Down
12 changes: 12 additions & 0 deletions snippets/terms.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const RootKey = () => {

return (
<Tooltip tip="The root key is a 256-bit secret from which other keys are derived for use throughout World App.">Root Key</Tooltip>
)
}

export const PersonalCustodyPackage = () => {
return (
<Tooltip tip="A Personal Custody Package (PCP) is a collection of files that represent a holder's World ID credential. It is stored on the user's device and optionally the user's backup.">Personal Custody Package</Tooltip>
)
}
5 changes: 3 additions & 2 deletions world-app/backup/advanced.mdx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
---
title: "Advanced"
title: "Advanced Topics on Backup"
sidebarTitle: "Advanced Topics"
description: "Internal advanced technical reference for the backup system."
---

## Encryption

All encryption operations uses libsodium's asymmetric [sealed_box](https://doc.libsodium.org/public-key_cryptography/sealed_boxes) primitive through the [crypto_box](https://crates.io/crates/crypto_box) crate.
All encryption operations use libsodium's asymmetric [sealed_box](https://doc.libsodium.org/public-key_cryptography/sealed_boxes) primitive through the [crypto_box](https://crates.io/crates/crypto_box) crate. A randomness source is required for sealed boxes to generate ephemeral key pairs for sealing. See [Cryptography](/world-app/cryptography) for more details on the randomness source.

## Apple Keychain

Expand Down
5 changes: 3 additions & 2 deletions world-app/backup/index.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: "Introduction to Backup"
description: "The backup system enables recovery and \"log in\" for World App."
sidebarTitle: "Introduction"
description: "The backup system enables logging in to World App."
---

import { UnsealedBackup, BackupEncryptionKeypair, EncryptedBackupEncryptionKeypair, BackupMetadata, MainFactor, SealedBackup, SyncFactor } from "/snippets/backup/terms.mdx";
Expand All @@ -22,7 +23,7 @@ Coming soon.
![Backup Composition](./images/backup-composition.svg)


- The <UnsealedBackup /> is a collection of raw files. It is stored locally only on-device.
- The <UnsealedBackup /> is a collection of raw files stored locally on the device only. The structure of the <UnsealedBackup /> is described in the [Backup Composition & Sync](/world-app/backup/structure-and-sync) section.
- The user encrypts the <UnsealedBackup /> with a <BackupEncryptionKeypair /> that's randomly generated by World App.
- The user then encrypts the <BackupEncryptionKeypair /> with each _Factor Secret_, creating $n$ <EncryptedBackupEncryptionKeypair />. After the <BackupEncryptionKeypair /> is encrypted with each _Factor Secret_, the user discards the secret key of the <BackupEncryptionKeypair />, and stores the public key (which is used to encrypt new versions of the <UnsealedBackup /> to **Sync** the backup).
- All the <EncryptedBackupEncryptionKeypair />s are stored in the <BackupMetadata />.
Expand Down
87 changes: 87 additions & 0 deletions world-app/backup/structure-and-sync.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
title: "Backup Sync & Internal Structure"
sidebarTitle: "Structure & Sync"
description: "Describes how the backup is synced between devices and used for authenticating new devices."
---

import { UnsealedBackup, SealedBackup } from "/snippets/backup/terms.mdx";
import { RootKey, PersonalCustodyPackage } from "/snippets/terms.mdx";


Syncing is the operation by which a user **updates** their backup from an authenticated device. A backup sync (`/sync`) is unidirectional, with a mobile client providing an update when new files are included in the backup. The client only fetches remote updates in certain scenarios (see below).

The <UnsealedBackup /> contains the encoded <RootKey /> for World App plus a set of raw files. The source of truth is the `BackupFormat` structure in [Bedrock](https://github.com/worldcoin/bedrock). The files back up all required self-custodial information that a user holds in their World App. In particular, today this is the user's World ID <PersonalCustodyPackage />s (or PCPs).

<Note>One of the challenges the system faces is that because the backup is end-to-end encrypted, the **Backup Service** cannot enforce any type of rules that prevent accidental data loss. For example, consider Client M in which the User gets their passport verified and hence obtains a PCP. If the user is also authenticated on Client N, and a backup sync is triggered from Client N, the PCP would be removed from the backup because Client N does not have it.</Note>


## Backup State Management

The backup system uses a **manifest-based approach** to prevent accidental data loss during syncs. Each backup contains a manifest that describes its contents and enforces proper versioning.

### The Manifest

Each backup ships with a manifest that describes the backup's contents. The manifest serves as a versioned ledger, ensuring clients always begin from the current state ($m_t$) and apply incremental updates to produce the next state ($m_{t+1}$).

```json
{
"version": 0,
"previous_manifest_hash": "0x1234567890000000000000000000000",
"files": [
{
"checksum": "0x1234567890000000000000000000000",
"file_path": "/personal_custody/unpack/me/here",
"designator": "orb_pcp"
}
]
}
```

Each state is defined as the `blake3` hash of the manifest file (raw bytes).

### Responsibilities

- **Client**: Bears sole responsibility for performing backup updates based on the current state. Must verify it's operating on the latest manifest before making changes.
- **Server**: Maintains a pointer to the current state hash. Validates state transitions during updates but cannot inspect encrypted contents.

### ManifestManager API (Client-Side)

The `ManifestManager` provides controlled access to backup modifications. Before any operation, it fetches the remote state hash to ensure consistency:

- If the local manifest is missing → prompts user to authenticate and download the remote state
- If `remote_manifest_hash == local_manifest_hash` → proceeds with updates
- If hashes differ → prompts user to authenticate and download the remote state

#### Available Methods

- **`store_file(designator, filePath)`** - Adds a new file to the backup. Verifies path uniqueness, computes checksum, triggers pack & upload.
- **`list_files(designator)`** - Returns all entries for the given designator.
- **`replace_all_files_for_designator(designator, newFilePath)`** - Replaces all existing entries for a designator with a new file.
- **`remove_file(filePath)`** - Removes a file entry from the manifest.

### Pack & Upload Process

When building and uploading a new backup version:

1. **Validate local manifest** - Error if missing; prompt to download remote.
2. **Build unsealed backup** - Collect all files from the manifest. Verify checksums match for every file.
3. **Submit sealed backup** - Include updated manifest inside. Report current and new manifest hashes to backend.
4. **Backend validation** - Verifies current hash matches recorded state before accepting update.

### Download & Unpack Process

When downloading and unpacking a remote backup:

1. **Decrypt sealed backup** - Extract and replace local manifest unconditionally.
2. **Unpack files** - Write each file to its declared `filePath`. Replace existing files (log errors for checksum mismatches).

This approach is safe because clients enforce explicit state transitions based on the current manifest.

### Startup Verification

On app startup, the client fetches the remote state checksum. If it differs from the local manifest, the user is prompted to authenticate and download the remote backup.

### Additional Safety Measures

- **Backend short-lived locks** - Prevents narrow race windows during updates, only one update at a time. Authoritative enforcement remains via manifest hash validation.
- **Hard links (Android Only)** - Hard links are created under `/backup/files/{checksum}` to guard against accidental deletion of source files. Links are removed on file removal.
17 changes: 17 additions & 0 deletions world-app/bedrock.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
title: "Bedrock — The Foundational Library"
sidebarTitle: "Bedrock"
description: "Bedrock is the foundational cross-platform library that powers World App. In particular, it enables the crypto wallet functionality for World App."
---

<Columns cols={2}>
<Card
title="Bedrock Repository"
icon="github"
href="https://github.com/worldcoin/bedrock"
arrow="true"
cta="View on GitHub"
>
Bedrock is open source and available on GitHub.
</Card>
</Columns>
8 changes: 8 additions & 0 deletions world-app/cryptography.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: "Cryptography"
description: "Cryptography reference for World App."
---

## CSPRNG and Randomness Source

Various operations in World App require a [CSPRNG](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator) (Cryptographically Secure Pseudo-Random Number Generator). For all such operations, we use the standard OS-provided CSPRNG. Most cryptographically sensitive operations in World App are handled by [Bedrock](/world-app/bedrock) foundational library. Bedrock accomplishes this by using the `OsRng` from the [rand](https://docs.rs/rand/latest/rand/rngs/struct.OsRng.html) crate. Under the hood, `OsRng` uses `getrandom` which uses the OS-provided CSPRNG (e.g. `getrandom(2)` syscall on Android (Linux), `SecRandomCopyBytes` on iOS).