# EncryptID: Unified Identity System for the r-Ecosystem

*Version 0.1 - February 2026*

---

## Executive Summary

**EncryptID** is a unified, self-sovereign identity system designed to work across all r-ecosystem applications (rspace.online, rwallet, rvote, rmaps, rfiles). It combines the security of hardware-backed authentication with the usability of passkeys, the flexibility of derived cryptographic keys, and the power of account abstraction smart wallets.

**Core Principles:**
- **No seed phrases** - Social recovery replaces mnemonic backup
- **Hardware-backed security** - WebAuthn/passkeys as the root of trust
- **Client-side encryption** - Keys never leave the user's device
- **Cross-app identity** - One login for all r-ecosystem apps
- **Web3 native** - Integrated smart wallet for on-chain operations

---

## Architecture Overview

```
+============================================================================+
||                           ENCRYPTID ARCHITECTURE                          ||
+============================================================================+

+----------------------------------------------------------------------------+
|                        LAYER 5: APPLICATION LAYER                          |
|                                                                            |
|   +-------------+  +-------------+  +-------------+  +-------------+       |
|   |   rspace    |  |   rwallet   |  |   rvote     |  |   rfiles    |       |
|   | (canvas)    |  | (treasury)  |  | (voting)    |  | (storage)   |       |
|   +------+------+  +------+------+  +------+------+  +------+------+       |
|          |                |                |                |              |
+----------|----------------|----------------|----------------|-------------+
           |                |                |                |
           v                v                v                v
+----------------------------------------------------------------------------+
|                      LAYER 4: SESSION & SSO LAYER                          |
|                                                                            |
|   +--------------------------------------------------------------------+   |
|   |                     EncryptID Session Service                      |   |
|   |                                                                    |   |
|   |  - JWT tokens (short-lived, refresh rotation)                      |   |
|   |  - Cross-app SSO via Related Origin Requests                       |   |
|   |  - Per-app capability scoping                                      |   |
|   |  - Session key caching for UX                                      |   |
|   +--------------------------------------------------------------------+   |
|                                                                            |
+--------------------------------+-------------------------------------------+
                                 |
                                 v
+----------------------------------------------------------------------------+
|                   LAYER 3: SMART WALLET LAYER (AA)                         |
|                                                                            |
|   +--------------------------------------------------------------------+   |
|   |              Account Abstraction Smart Wallet (ERC-4337)           |   |
|   |                                                                    |   |
|   |   +------------------+  +------------------+  +------------------+ |   |
|   |   |  Passkey Signer  |  | Session Keys    |  | Social Recovery  | |   |
|   |   |  (WebAuthn P256) |  | (time-limited)  |  | (Guardian Module)| |   |
|   |   +------------------+  +------------------+  +------------------+ |   |
|   |                                                                    |   |
|   |   Features:                                                        |   |
|   |   - Gasless transactions (paymaster)                               |   |
|   |   - Batched operations                                             |   |
|   |   - Spending limits & policies                                     |   |
|   |   - No seed phrase needed                                          |   |
|   +--------------------------------------------------------------------+   |
|                                                                            |
+--------------------------------+-------------------------------------------+
                                 |
                                 v
+----------------------------------------------------------------------------+
|                    LAYER 2: DERIVED KEYS LAYER                             |
|                                                                            |
|   +--------------------------------------------------------------------+   |
|   |                WebCrypto Key Derivation (HKDF)                     |   |
|   |                                                                    |   |
|   |   Source: WebAuthn PRF output OR passphrase-derived master key    |   |
|   |                                                                    |   |
|   |   +---------------+  +---------------+  +---------------+          |   |
|   |   | Encryption    |  | Signing       |  | DID           |          |   |
|   |   | Key (AES-256) |  | Key (P-256)   |  | Key (Ed25519) |          |   |
|   |   +-------+-------+  +-------+-------+  +-------+-------+          |   |
|   |           |                  |                  |                  |   |
|   |           v                  v                  v                  |   |
|   |   +---------------+  +---------------+  +---------------+          |   |
|   |   | rfiles E2E    |  | rvote ballot  |  | did:key:z6Mk  |          |   |
|   |   | rspace boards |  | signatures    |  | identity      |          |   |
|   |   +---------------+  +---------------+  +---------------+          |   |
|   +--------------------------------------------------------------------+   |
|                                                                            |
+--------------------------------+-------------------------------------------+
                                 |
                                 v
+----------------------------------------------------------------------------+
|                  LAYER 1: PRIMARY AUTHENTICATION                           |
|                                                                            |
|   +--------------------------------------------------------------------+   |
|   |                      WebAuthn / Passkeys                           |   |
|   |                                                                    |   |
|   |   +------------------+  +------------------+  +------------------+ |   |
|   |   | Platform Passkey |  | Security Key    |  | Cross-Device     | |   |
|   |   | (iCloud/Google)  |  | (YubiKey/Titan) |  | (QR/Bluetooth)   | |   |
|   |   +------------------+  +------------------+  +------------------+ |   |
|   |                                                                    |   |
|   |   Properties:                                                      |   |
|   |   - Phishing-resistant (origin-bound)                              |   |
|   |   - Hardware-backed (TPM/Secure Enclave)                           |   |
|   |   - Biometric (fingerprint/face)                                   |   |
|   |   - Syncs across devices (platform providers)                      |   |
|   +--------------------------------------------------------------------+   |
|                                                                            |
+============================================================================+
```

---

## Layer 1: Primary Authentication (WebAuthn/Passkeys)

### Why WebAuthn as the Foundation

| Property | Benefit |
|----------|---------|
| **Origin-bound** | Credentials only work on the registered domain - phishing-resistant |
| **Hardware-backed** | Private key stored in TPM/Secure Enclave - can't be extracted |
| **Biometric** | Face/fingerprint verification - something you *are* |
| **Synced** | Platform passkeys sync via iCloud Keychain, Google Password Manager |
| **No passwords** | Nothing to remember, nothing to steal |

### Implementation

```typescript
// EncryptID Registration Flow
async function registerEncryptID(username: string): Promise<EncryptIDCredential> {
  const challenge = await fetchChallenge('/api/encryptid/register/challenge');

  const credential = await navigator.credentials.create({
    publicKey: {
      challenge: base64ToBuffer(challenge),
      rp: {
        name: "EncryptID",
        id: "encryptid.online"  // Shared RP ID for all r-apps
      },
      user: {
        id: crypto.getRandomValues(new Uint8Array(32)),
        name: username,
        displayName: username
      },
      pubKeyCredParams: [
        { alg: -7, type: "public-key" },    // ES256 (P-256)
        { alg: -257, type: "public-key" }   // RS256 (fallback)
      ],
      authenticatorSelection: {
        residentKey: "required",           // Discoverable credential
        userVerification: "required",      // Biometric/PIN required
        authenticatorAttachment: "platform" // Prefer built-in authenticator
      },
      attestation: "none",                 // Privacy-preserving
      extensions: {
        prf: {                             // PRF extension for key derivation
          eval: {
            first: base64ToBuffer(await generateSalt("encryptid-master"))
          }
        },
        credProps: true                    // Get credential properties
      }
    }
  });

  return processRegistration(credential);
}
```

### PRF Extension Support Status (2026)

| Platform | Browser | PRF Support | Notes |
|----------|---------|-------------|-------|
| **Windows** | Chrome/Edge | Full | TPM-backed |
| **macOS** | Chrome/Safari | Full | Secure Enclave |
| **Android** | Chrome | Full | TEE/StrongBox |
| **iOS/iPadOS** | Safari | Partial | Works with iCloud Keychain passkeys |
| **Linux** | Chrome | Varies | Depends on FIDO2 library |

**Fallback Strategy:** For authenticators without PRF support, derive master key from a user-provided passphrase using Argon2id + HKDF.

### Related Origin Requests for Cross-App SSO

Since r-apps span multiple domains, we use [Related Origin Requests](https://passkeys.dev/docs/advanced/related-origins/):

```
// File: https://encryptid.online/.well-known/webauthn
{
  "origins": [
    "https://rspace.online",
    "https://rwallet.online",
    "https://rvote.online",
    "https://rmaps.online",
    "https://rfiles.online",
    "https://app.rspace.online",
    "https://dev.rspace.online"
  ]
}
```

This allows a passkey registered with RP ID `encryptid.online` to authenticate on any of these origins.

**Browser Support:**
- Chrome: Full support
- Safari: Full support
- Firefox: Under consideration (use iframe fallback)

---

## Layer 2: Derived Keys (WebCrypto API)

### Key Derivation Hierarchy

```
                    +---------------------------+
                    |   WebAuthn PRF Output     |
                    |   (32 bytes from HMAC)    |
                    +-------------+-------------+
                                  |
                                  v
                    +---------------------------+
                    |       Master Key          |
                    |   (HKDF extract step)     |
                    +-------------+-------------+
                                  |
          +-----------------------+-----------------------+
          |                       |                       |
          v                       v                       v
+-------------------+   +-------------------+   +-------------------+
|   Encryption Key  |   |   Signing Key     |   |   DID Key         |
|   (AES-256-GCM)   |   |   (ECDSA P-256)   |   |   (Ed25519)       |
+-------------------+   +-------------------+   +-------------------+
        |                       |                       |
        v                       v                       v
+-------------------+   +-------------------+   +-------------------+
| rfiles encryption |   | rvote signatures  |   | did:key identity  |
| rspace E2E boards |   | rspace authorship |   | verifiable creds  |
+-------------------+   +-------------------+   +-------------------+
```

### Implementation

```typescript
// Key Derivation from PRF output
class EncryptIDKeyDerivation {
  private masterKey: CryptoKey;

  async initFromPRF(prfOutput: ArrayBuffer): Promise<void> {
    // Import PRF output as HKDF key material
    this.masterKey = await crypto.subtle.importKey(
      "raw",
      prfOutput,
      { name: "HKDF" },
      false,
      ["deriveKey", "deriveBits"]
    );
  }

  async initFromPassphrase(passphrase: string, salt: Uint8Array): Promise<void> {
    // Fallback: derive from passphrase using PBKDF2
    const encoder = new TextEncoder();
    const passphraseKey = await crypto.subtle.importKey(
      "raw",
      encoder.encode(passphrase),
      { name: "PBKDF2" },
      false,
      ["deriveBits", "deriveKey"]
    );

    const masterBits = await crypto.subtle.deriveBits(
      {
        name: "PBKDF2",
        salt: salt,
        iterations: 600000,  // OWASP 2023 recommendation
        hash: "SHA-256"
      },
      passphraseKey,
      256
    );

    this.masterKey = await crypto.subtle.importKey(
      "raw",
      masterBits,
      { name: "HKDF" },
      false,
      ["deriveKey", "deriveBits"]
    );
  }

  async deriveEncryptionKey(): Promise<CryptoKey> {
    return crypto.subtle.deriveKey(
      {
        name: "HKDF",
        hash: "SHA-256",
        salt: new TextEncoder().encode("encryptid-encryption-v1"),
        info: new TextEncoder().encode("AES-256-GCM")
      },
      this.masterKey,
      { name: "AES-GCM", length: 256 },
      false,  // Not extractable
      ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
    );
  }

  async deriveSigningKeyPair(): Promise<CryptoKeyPair> {
    // Derive deterministic seed for signing key
    const seed = await crypto.subtle.deriveBits(
      {
        name: "HKDF",
        hash: "SHA-256",
        salt: new TextEncoder().encode("encryptid-signing-v1"),
        info: new TextEncoder().encode("ECDSA-P256")
      },
      this.masterKey,
      256
    );

    // Use seed to generate deterministic P-256 key
    // (Implementation uses noble-curves or similar)
    return generateP256FromSeed(seed);
  }

  async deriveDIDKey(): Promise<{ did: string; privateKey: Uint8Array }> {
    // Derive Ed25519 key for DID
    const seed = await crypto.subtle.deriveBits(
      {
        name: "HKDF",
        hash: "SHA-256",
        salt: new TextEncoder().encode("encryptid-did-v1"),
        info: new TextEncoder().encode("Ed25519")
      },
      this.masterKey,
      256
    );

    // Generate Ed25519 keypair from seed
    const keyPair = ed25519.generateKeyPairFromSeed(new Uint8Array(seed));

    // Format as did:key
    const did = `did:key:${base58btc.encode(
      new Uint8Array([0xed, 0x01, ...keyPair.publicKey])
    )}`;

    return { did, privateKey: keyPair.privateKey };
  }
}
```

### Key Usage by Application

| Application | Encryption Key | Signing Key | DID Key | Wallet |
|-------------|----------------|-------------|---------|--------|
| **rspace** | Private boards, E2E content | Document signatures, authorship | Cross-app identity | Premium features |
| **rwallet** | - | Transaction signing | Identity verification | Treasury ops |
| **rvote** | Encrypted ballot metadata | Ballot signatures | Voter identity | On-chain voting |
| **rmaps** | Private location data | Contribution signatures | Contributor identity | - |
| **rfiles** | E2E file encryption | File signatures | Sharing identity | Storage payments |

---

## Layer 3: Smart Wallet (Account Abstraction)

### Why Account Abstraction?

Traditional EOA (Externally Owned Account) wallets have critical UX problems:
- Seed phrases are confusing and easily lost
- No built-in recovery mechanism
- Gas required for every transaction
- Single point of failure (one key = full access)

Account Abstraction (ERC-4337) smart wallets solve these:

| Feature | EOA Wallet | AA Smart Wallet |
|---------|-----------|-----------------|
| **Key management** | Seed phrase | Passkey + social recovery |
| **Gas** | User pays ETH | Paymaster can sponsor |
| **Recovery** | Seed phrase or nothing | Guardian-based recovery |
| **Policies** | None | Spending limits, time locks |
| **Batching** | One tx at a time | Multiple ops in one tx |

### Provider Comparison

| Provider | Passkey Support | Social Recovery | Pricing | Best For |
|----------|-----------------|-----------------|---------|----------|
| **[ZeroDev](https://zerodev.app/)** | Native (Turnkey) | Guardian module | Usage-based | Full control, custom flows |
| **[Safe](https://safe.global/)** | Passkey module | Multi-sig native | Free (gas only) | DAOs, shared treasuries |
| **[Privy](https://privy.io/)** | Native | Managed recovery | Enterprise pricing | Quick integration |
| **[Turnkey](https://turnkey.com/)** | Native (TEE) | Custom | Volume-based | Infrastructure layer |

### Recommended Architecture: ZeroDev + Safe Hybrid

```
+============================================================================+
|                    ENCRYPTID SMART WALLET ARCHITECTURE                      |
+============================================================================+

                         +---------------------------+
                         |      User's Passkey       |
                         | (WebAuthn P-256 on device)|
                         +-------------+-------------+
                                       |
                                       v
                         +---------------------------+
                         |     Turnkey TEE Signer    |
                         |  (Secure enclave signing) |
                         +-------------+-------------+
                                       |
                    +------------------+------------------+
                    |                                     |
                    v                                     v
+-------------------------------+       +-------------------------------+
|    Personal Smart Wallet      |       |   Community Treasury (Safe)   |
|         (ZeroDev Kernel)      |       |        Multi-sig Wallet       |
+-------------------------------+       +-------------------------------+
|                               |       |                               |
|  Owner: Passkey Validator     |       |  Signers:                     |
|                               |       |  - User's EncryptID           |
|  Modules:                     |       |  - Other community members    |
|  - Session Key (daily ops)    |       |  - Guardian (recovery)        |
|  - Recovery (guardians)       |       |                               |
|  - Spending Limits            |       |  Threshold: 2 of 3            |
|                               |       |                               |
+-------------------------------+       +-------------------------------+
           |                                       |
           v                                       v
+-------------------------------+       +-------------------------------+
|        Use Cases:             |       |        Use Cases:             |
|  - Personal rwallet           |       |  - Community rwallet          |
|  - rvote governance           |       |  - Shared treasury            |
|  - rfiles payments            |       |  - Grant disbursement         |
+-------------------------------+       +-------------------------------+
```

### Implementation

```typescript
import { createKernelAccount, createKernelAccountClient } from "@zerodev/sdk";
import { toWebAuthnKey, toPasskeyValidator } from "@zerodev/passkey-validator";
import { toECDSASigner } from "@zerodev/permissions";

class EncryptIDWallet {
  private kernelAccount: KernelAccount;
  private kernelClient: KernelAccountClient;

  async initialize(webAuthnCredential: PublicKeyCredential): Promise<string> {
    // Create WebAuthn-based validator
    const webAuthnKey = await toWebAuthnKey({
      passkeyName: "EncryptID",
      passkeyServerUrl: "https://encryptid.online/passkey",
      credential: webAuthnCredential
    });

    const passkeyValidator = await toPasskeyValidator(publicClient, {
      webAuthnKey,
      entryPoint: ENTRYPOINT_ADDRESS_V07,
      kernelVersion: KERNEL_V3_1
    });

    // Create kernel account with passkey as owner
    this.kernelAccount = await createKernelAccount(publicClient, {
      plugins: {
        sudo: passkeyValidator  // Passkey has full control
      },
      entryPoint: ENTRYPOINT_ADDRESS_V07,
      kernelVersion: KERNEL_V3_1
    });

    // Create client with paymaster for gasless UX
    this.kernelClient = createKernelAccountClient({
      account: this.kernelAccount,
      chain: base,  // or arbitrum, optimism, etc.
      bundlerTransport: http(BUNDLER_URL),
      paymaster: createZeroDevPaymasterClient({
        chain: base,
        transport: http(PAYMASTER_URL)
      })
    });

    return this.kernelAccount.address;
  }

  // Create session key for frictionless UX
  async createSessionKey(permissions: Permission[], duration: number): Promise<SessionKey> {
    const sessionKey = generatePrivateKey();
    const sessionSigner = privateKeyToAccount(sessionKey);

    const sessionKeyValidator = await toPermissionValidator(publicClient, {
      entryPoint: ENTRYPOINT_ADDRESS_V07,
      kernelVersion: KERNEL_V3_1,
      signer: toECDSASigner({ signer: sessionSigner }),
      policies: [
        toCallPolicy({
          permissions: permissions  // e.g., only call specific contracts
        }),
        toTimestampPolicy({
          validUntil: Math.floor(Date.now() / 1000) + duration
        }),
        toSpendingLimitPolicy({
          limits: [{ token: ETH_ADDRESS, limit: parseEther("0.1") }]
        })
      ]
    });

    // User approves session key with passkey (one biometric prompt)
    await this.kernelClient.installModule({
      module: sessionKeyValidator.address,
      data: sessionKeyValidator.initData
    });

    return { privateKey: sessionKey, validator: sessionKeyValidator };
  }
}
```

---

## Layer 4: Social Recovery (No Seed Phrases!)

### Design Philosophy

> "The goal of social recovery is to avoid a single point of failure. If you lose your device, you should not lose your assets. If your guardians conspire against you, they should not be able to steal your assets."
> — [Vitalik Buterin](https://vitalik.eth.limo/general/2021/01/11/recovery.html)

### Guardian Configuration

```
+============================================================================+
|                     ENCRYPTID SOCIAL RECOVERY MODEL                         |
+============================================================================+

                    +---------------------------+
                    |     Recovery Threshold    |
                    |     3 of 5 guardians      |
                    +---------------------------+
                                  |
        +------------+------------+------------+------------+
        |            |            |            |            |
        v            v            v            v            v
+-------------+ +-------------+ +-------------+ +-------------+ +-------------+
|  Guardian 1 | |  Guardian 2 | |  Guardian 3 | |  Guardian 4 | |  Guardian 5 |
+-------------+ +-------------+ +-------------+ +-------------+ +-------------+
|             | |             | |             | |             | |             |
| Secondary   | | Trusted     | | Trusted     | | Hardware    | | Institutional|
| Passkey     | | Friend A    | | Friend B    | | Key         | | Guardian    |
| (YubiKey)   | | (their      | | (their      | | (offline    | | (service)   |
|             | | EncryptID)  | | EncryptID)  | | backup)     | |             |
+-------------+ +-------------+ +-------------+ +-------------+ +-------------+

Recovery Rules:
- Time-lock: 48-hour delay before recovery completes
- Notification: User notified immediately when recovery initiated
- Cancellation: User can cancel with any valid authenticator
- Guardian privacy: Guardians don't know each other's identities
```

### Guardian Types

| Type | Description | Pros | Cons |
|------|-------------|------|------|
| **Secondary Passkey** | Another device you own (YubiKey, second phone) | Always available, you control | Can lose both devices |
| **Trusted Contact** | Friend/family with EncryptID | Human judgment, diverse access | Relationship changes |
| **Hardware Key** | Offline YubiKey stored securely | Immune to remote attacks | Physical access needed |
| **Institutional** | Service provider (e.g., rspace.online) | Professional, always available | Trust in service |
| **Time-delayed Self** | Your own auth after N days | No external trust needed | Attacker has same delay |

### Implementation

```typescript
// ZeroDev Recovery Module
class EncryptIDRecovery {
  async setupGuardians(guardians: Guardian[]): Promise<void> {
    const recoveryConfig = {
      threshold: 3,  // 3 of 5 required
      delay: 48 * 60 * 60,  // 48 hours
      guardians: guardians.map(g => ({
        address: g.address,
        weight: g.weight || 1
      }))
    };

    const recoveryPlugin = await createRecoveryPlugin(recoveryConfig);

    await this.kernelClient.installModule({
      module: recoveryPlugin.address,
      data: recoveryPlugin.initData
    });
  }

  async initiateRecovery(
    newOwner: Address,
    guardianSignatures: Signature[]
  ): Promise<RecoveryRequest> {
    // Guardian signs recovery request
    // This starts the time-lock countdown
    const recoveryId = await this.kernelClient.sendUserOperation({
      userOperation: {
        callData: encodeFunctionData({
          abi: recoveryAbi,
          functionName: 'initiateRecovery',
          args: [newOwner, guardianSignatures]
        })
      }
    });

    // Notify user through all channels
    await notifyUserOfRecovery(this.kernelAccount.address, recoveryId);

    return { recoveryId, completesAt: Date.now() + 48 * 60 * 60 * 1000 };
  }

  async completeRecovery(recoveryId: string): Promise<void> {
    // After time-lock, anyone can complete
    await this.kernelClient.sendUserOperation({
      userOperation: {
        callData: encodeFunctionData({
          abi: recoveryAbi,
          functionName: 'completeRecovery',
          args: [recoveryId]
        })
      }
    });
  }

  async cancelRecovery(recoveryId: string): Promise<void> {
    // User can cancel with any valid auth method
    await this.kernelClient.sendUserOperation({
      userOperation: {
        callData: encodeFunctionData({
          abi: recoveryAbi,
          functionName: 'cancelRecovery',
          args: [recoveryId]
        })
      }
    });
  }
}
```

### Guardian Privacy

Guardians don't need to know each other - this prevents collusion:

```typescript
// Store guardian list as hash on-chain
const guardianListHash = keccak256(
  encodePacked(['address[]'], [guardianAddresses.sort()])
);

// During recovery, reveal full list
function verifyGuardians(addresses: Address[], hash: bytes32): boolean {
  return keccak256(encodePacked(['address[]'], [addresses.sort()])) === hash;
}
```

### Best Practices (per [Vitalik](https://vitalik.eth.limo/general/2021/01/11/recovery.html))

1. **High guardian count (5-7)** for better security
2. **Diverse social circles** - family, friends, colleagues, institutions
3. **Privacy-preserving** - guardians don't know each other
4. **Time-lock** - gives user window to cancel malicious recovery
5. **Regular verification** - periodically confirm guardians are reachable

---

## Layer 5: Session & Cross-App SSO

### Session Architecture

```
+============================================================================+
|                        ENCRYPTID SESSION FLOW                               |
+============================================================================+

    User                  encryptid.online              r-app (e.g., rspace)
      |                         |                              |
      |  1. Visit rspace.online |                              |
      |------------------------>|                              |
      |                         |  2. Check for EncryptID      |
      |                         |     session cookie           |
      |                         |----------------------------->|
      |                         |                              |
      |  3. No session, redirect to encryptid.online/auth      |
      |<-------------------------------------------------------|
      |                         |                              |
      |  4. WebAuthn authenticate                              |
      |------------------------>|                              |
      |                         |                              |
      |  5. Derive session keys (if needed)                    |
      |<------------------------|                              |
      |                         |                              |
      |  6. Issue session token |                              |
      |     (JWT + refresh)     |                              |
      |<------------------------|                              |
      |                         |                              |
      |  7. Redirect back with auth code                       |
      |------------------------------------------------------>|
      |                         |                              |
      |                         |  8. Exchange code for tokens |
      |                         |<-----------------------------|
      |                         |                              |
      |  9. Session established, user authenticated            |
      |<-------------------------------------------------------|
```

### Token Structure

```typescript
interface EncryptIDSession {
  // Standard JWT claims
  iss: "https://encryptid.online";
  sub: string;           // DID (did:key:z6Mk...)
  aud: string[];         // Authorized apps ["rspace.online", "rwallet.online"]
  iat: number;
  exp: number;           // Short-lived (15 min)

  // EncryptID-specific claims
  eid: {
    walletAddress?: string;        // AA wallet if deployed
    credentialId: string;          // WebAuthn credential ID
    authLevel: 1 | 2 | 3 | 4;      // Security level of this session
    capabilities: {
      encrypt: boolean;            // Has derived encryption key
      sign: boolean;               // Has derived signing key
      wallet: boolean;             // Can authorize wallet ops
    };
    recoveryConfigured: boolean;   // Has social recovery set up
  };
}
```

### Security Levels

```typescript
enum AuthLevel {
  // Level 1: Session token only (cookie)
  // Can: View public content, read-only operations
  // Cannot: Modify data, sign anything
  BASIC = 1,

  // Level 2: Recent WebAuthn (within 15 min)
  // Can: Create/edit content, standard operations
  // Cannot: High-value transactions, key operations
  STANDARD = 2,

  // Level 3: Fresh WebAuthn (just authenticated)
  // Can: Sign votes, approve transactions
  // Cannot: Recovery operations, export keys
  ELEVATED = 3,

  // Level 4: Fresh WebAuthn + explicit consent
  // Can: Everything including recovery, key export
  CRITICAL = 4
}

// Operation requirements
const operationLevels = {
  'rspace:view-public': AuthLevel.BASIC,
  'rspace:edit-board': AuthLevel.STANDARD,
  'rspace:encrypt-board': AuthLevel.ELEVATED,

  'rwallet:view-balance': AuthLevel.BASIC,
  'rwallet:send-small': AuthLevel.STANDARD,
  'rwallet:send-large': AuthLevel.ELEVATED,
  'rwallet:add-guardian': AuthLevel.CRITICAL,

  'rvote:view-proposals': AuthLevel.BASIC,
  'rvote:cast-vote': AuthLevel.ELEVATED,

  'rfiles:download-own': AuthLevel.STANDARD,
  'rfiles:upload': AuthLevel.STANDARD,
  'rfiles:share': AuthLevel.ELEVATED,
  'rfiles:export-keys': AuthLevel.CRITICAL
};
```

---

## Migration Path from CryptID

### Phase 1: Parallel Systems (Months 1-2)

```
+----------------------------------+
|         Current CryptID          |
|  (WebCrypto keypairs in IDB)     |
+----------------------------------+
              ||
              || Users can link
              || EncryptID passkey
              vv
+----------------------------------+
|         EncryptID                |
|  (WebAuthn + derived keys)       |
+----------------------------------+

- Existing CryptID users continue working
- Optional: Link EncryptID passkey to existing account
- New users default to EncryptID
- Both auth methods valid during transition
```

### Phase 2: Key Migration (Months 2-3)

```typescript
async function migrateCryptIDToEncryptID(
  cryptidKeyPair: CryptoKeyPair,
  encryptidMasterKey: CryptoKey
): Promise<void> {
  // 1. Export CryptID private key (if exportable)
  //    or re-encrypt data with new keys

  // 2. For each encrypted item:
  //    - Decrypt with CryptID key
  //    - Re-encrypt with EncryptID-derived key

  // 3. Update identity mappings
  //    - Link old CryptID public key to new DID
  //    - Maintain backward compatibility

  // 4. Mark migration complete
}
```

### Phase 3: CryptID Sunset (Months 3-6)

- New accounts: EncryptID only
- Existing accounts: Prompted to upgrade
- CryptID becomes legacy fallback
- Eventually: Remove CryptID support

---

## Security Considerations

### Threat Model

| Threat | Mitigation |
|--------|------------|
| **Phishing** | WebAuthn is origin-bound; passkeys can't be used on fake sites |
| **Device theft** | Biometric required; derived keys not extractable |
| **Server compromise** | Keys derived client-side; server never sees private keys |
| **Guardian collusion** | High threshold (3/5), diverse selection, time-lock |
| **Malicious recovery** | 48h delay, user notification, cancellation window |
| **Key extraction** | WebCrypto keys marked non-extractable |
| **PRF unavailable** | Fallback to passphrase-derived with strong KDF |

### PRF Key Binding Warning

> "Data encrypted with PRF-derived keys is bound exclusively to the specific passkey. Losing the passkey will permanently render the encrypted data inaccessible."
> — [Corbado](https://www.corbado.com/blog/passkeys-prf-webauthn)

**Mitigation:**
1. Social recovery enables passkey rotation
2. Multiple passkeys (backup hardware key)
3. Encrypted key escrow (wrapped with recovery keys)

### Browser/Authenticator Compatibility

Test matrix for WebAuthn features:

| Feature | Chrome | Safari | Firefox | Edge |
|---------|--------|--------|---------|------|
| Basic WebAuthn | Yes | Yes | Yes | Yes |
| Discoverable Credentials | Yes | Yes | Yes | Yes |
| PRF Extension | Yes | Yes | No | Yes |
| Related Origins | Yes | Yes | No | Yes |
| Cross-device (Hybrid) | Yes | Yes | Partial | Yes |

---

## Implementation Roadmap

### Sprint 1: Foundation (2 weeks)
- [ ] Set up encryptid.online domain
- [ ] Implement WebAuthn registration/authentication
- [ ] Create Related Origins configuration
- [ ] Basic session token issuance

### Sprint 2: Key Derivation (2 weeks)
- [ ] Implement PRF-based key derivation
- [ ] Passphrase fallback for non-PRF authenticators
- [ ] Encryption key integration with rfiles
- [ ] Signing key integration with rvote

### Sprint 3: Smart Wallet (3 weeks)
- [ ] ZeroDev integration
- [ ] Passkey validator deployment
- [ ] Session key module
- [ ] Paymaster setup for gasless UX

### Sprint 4: Social Recovery (2 weeks)
- [ ] Guardian configuration UI
- [ ] Recovery initiation flow
- [ ] Time-lock and notification system
- [ ] Recovery completion and cancellation

### Sprint 5: Cross-App Integration (2 weeks)
- [ ] rspace.online integration
- [ ] rwallet.online integration
- [ ] rvote.online integration
- [ ] rfiles.online integration
- [ ] rmaps.online integration

### Sprint 6: Migration & Polish (2 weeks)
- [ ] CryptID migration tools
- [ ] User onboarding flow
- [ ] Documentation
- [ ] Security audit

---

## References

### WebAuthn & Passkeys
- [WebAuthn PRF Extension Guide (Yubico)](https://developers.yubico.com/WebAuthn/Concepts/PRF_Extension/Developers_Guide_to_PRF.html)
- [Passkeys & WebAuthn PRF for E2E Encryption (Corbado)](https://www.corbado.com/blog/passkeys-prf-webauthn)
- [Related Origin Requests (passkeys.dev)](https://passkeys.dev/docs/advanced/related-origins/)
- [Cross-Domain Passkeys (web.dev)](https://web.dev/articles/webauthn-related-origin-requests)

### Account Abstraction
- [ZeroDev Documentation](https://docs.zerodev.app/)
- [ZeroDev Recovery](https://docs-v4.zerodev.app/use-wallets/recovery)
- [Safe Passkey Module](https://docs.safe.global/advanced/passkeys/passkeys-safe)
- [Safe Passkey Signer](https://docs.safe.global/sdk/signers/passkeys)

### Social Recovery
- [Why We Need Social Recovery Wallets (Vitalik Buterin)](https://vitalik.eth.limo/general/2021/01/11/recovery.html)
- [Social Recovery Best Practices](https://yellow.com/learn/social-recovery-wallets-can-they-solve-the-seed-phrase-problem-complete-2025-guide)

### Infrastructure
- [Turnkey Whitepaper](https://whitepaper.turnkey.com/architecture)
- [Turnkey Embedded Wallets](https://www.turnkey.com/embedded-wallets)
- [Privy Documentation](https://docs.privy.io/)

### Decentralized Identity
- [DID Core Specification (W3C)](https://www.w3.org/TR/did-core/)
- [did:key Method](https://w3c-ccg.github.io/did-method-key/)
- [Decentralized Identity Guide 2025 (Dock)](https://www.dock.io/post/decentralized-identity)

---

*Document version: 0.1*
*Last updated: February 5, 2026*
*Author: Jeff Emmett with Claude*
