How the Tiered Trust Mechanism in BitChat Affects Message Envelope Deposits

BitChat’s tiered trust system prioritizes message envelopes from mutually-vouched "favorite" peers with unlimited quotas while strictly limiting or rejecting deposits from lower-trust tiers to prevent storage exhaustion.

The permissionlesstech/bitchat repository implements a store-and-forward messaging protocol where devices act as couriers for offline peers. The tiered trust mechanism governs how many message envelopes each peer can deposit and which messages survive when storage capacity reaches its limit. This ensures trusted contacts maintain reliable message delivery while untrusted actors cannot flood the network.

Understanding the Three Trust Tiers

BitChat categorizes every peer into one of three logical trust levels that determine envelope deposit privileges. The trust tier evaluation occurs in components like SecureIdentityStateManager before reaching the storage layer.

Favorite – Established when two peers mutually vouch for each other (both appear in each other’s favorite lists). These deposits receive unlimited per-depositor quotas (up to 5 envelopes), are protected from eviction by lower-tier mail, and only face removal when the store fills completely with favorite-tier envelopes.

Verified – Assigned when a peer’s announce signature has been cryptographically verified but no mutual vouch exists. These deposits face strict caps: maximum 2 envelopes per depositor and a global pool limit of 20 verified envelopes across all peers. When storage fills, verified envelopes are evicted first.

Untrusted – Applies to peers with neither mutual vouch nor verified signature. The deposit method rejects these deposits immediately; callers must enforce this policy before invoking the store.

How Deposit Limits and Quotas Work

The CourierStore.swift file enforces resource caps through the deposit(_:from:tier:) method, which accepts a CourierDepositTier enum value. The store itself does not determine trust levels—it only applies the quotas associated with the tier passed to it.

Per-depositor limits restrict how many envelopes a single peer can store:

  • Favorite tier: Maximum 5 envelopes per depositor (Limits.maxPerFavoriteDepositor)
  • Verified tier: Maximum 2 envelopes per depositor (Limits.maxPerVerifiedDepositor)

Global limits constrain the total store capacity:

  • Total capacity: 40 envelopes maximum (Limits.maxEnvelopes)
  • Verified pool cap: 20 verified envelopes maximum across all depositors (Limits.maxVerifiedEnvelopes)

When the global verified pool reaches 20 envelopes, the store rejects additional verified deposits even if total capacity remains available.

The Eviction Policy When Storage Is Full

When the store reaches its 40-envelope maximum, the eviction logic in CourierStore applies a strict priority hierarchy to make room for new deposits:

  1. First, it searches for the oldest verified envelope and removes it.
  2. If no verified envelopes exist and the incoming deposit is favorite tier, it evicts the oldest favorite envelope.
  3. If no verified envelopes exist and the incoming deposit is verified tier, the deposit is rejected.

This policy ensures favorite mail can always be carried while verified mail serves as a buffer that absorbs storage pressure before affecting trusted communications.

Implementation in CourierStore.swift

The deposit logic resides in bitchat/Services/Courier/CourierStore.swift, which defines the trust tiers and enforcement rules.

enum CourierDepositTier: String, Codable {
    case favorite        // Mutual favorites – highest priority
    case verified        // Signature-verified announce – limited quota
}

The deposit method implements the quota checks and eviction strategy:

func deposit(_ envelope: CourierEnvelope,
             from depositorNoiseKey: Data,
             tier: CourierDepositTier = .favorite) -> Bool {
    // … basic envelope validation omitted …
    return queue.sync {
        pruneExpiredLocked(at: date)

        // Per-depositor quota enforcement
        let perDepositorLimit = tier == .favorite
            ? Limits.maxPerFavoriteDepositor
            : Limits.maxPerVerifiedDepositor
        guard envelopes.filter({ $0.depositorNoiseKey == depositorNoiseKey }).count
                < perDepositorLimit else { return false }

        // Verified-tier global pool limit
        if tier == .verified,
           envelopes.filter({ $0.tier == .verified }).count >= Limits.maxVerifiedEnvelopes {
            return false
        }

        // Global capacity & eviction policy
        if envelopes.count >= Limits.maxEnvelopes {
            if let victim = envelopes.firstIndex(where: { $0.tier == .verified }) {
                envelopes.remove(at: victim)               // evict verified first
            } else if tier == .favorite {
                envelopes.removeFirst()                     // evict oldest favorite
            } else {
                return false                               // reject untrusted deposit
            }
        }

        // Store the new envelope
        envelopes.append(StoredEnvelope(..., tier: tier, ...))
        persistLocked()
        return true
    }
}

The courierEnvelope message type used for transport is defined in localPackages/BitFoundation/Sources/BitFoundation/MessageType.swift:

case courierEnvelope = 0x04 // Store-and-forward envelope carried by a trusted peer

Integration with Identity and Vouch Systems

While CourierStore enforces quotas, the trust tier determination happens upstream in the identity layer. The SecureIdentityStateManager.swift tracks social identities and maps peers to trust levels, while ChatVouchCoordinator.swift emits notifications when trust relationships change (such as mutual vouching).

When depositing an envelope, the caller determines the tier before invoking the store:

// Determine peer trust tier based on mutual vouch status
let peerKey = somePeer.noiseStaticKey
let tier: CourierDepositTier = TrustManager.trustTier(for: peerKey)

// Attempt deposit with appropriate tier
let envelope = CourierEnvelope(
    recipientTag: recipientTag,
    expiry: expiryMs,
    ciphertext: encryptedPayload,
    copies: 4,
    prekeyID: nil)

let stored = CourierStore.shared.deposit(envelope,
                                         from: myNoiseKey,
                                         tier: tier)

Summary

  • BitChat uses three trust tiers (Favorite, Verified, Untrusted) to govern message envelope deposits in its courier store-and-forward system.
  • Favorite peers receive generous quotas (5 envelopes each) and eviction protection, while Verified peers face strict limits (2 envelopes each, 20 global) and serve as the first eviction candidates.
  • The CourierStore.deposit(_:from:tier:) method in CourierStore.swift enforces these limits but does not determine trust; identity managers classify peers before deposit.
  • When storage reaches its 40-envelope capacity, the system evicts verified mail first, then oldest favorite mail only if necessary, ensuring trusted communications remain prioritized.

Frequently Asked Questions

What happens when the courier store reaches maximum capacity?

When the store holds 40 envelopes (Limits.maxEnvelopes), new deposits trigger an eviction sequence. The system first removes the oldest envelope from the verified tier. If no verified envelopes remain and the incoming deposit is favorite-tier, it removes the oldest favorite envelope. Verified deposits are rejected if only favorite envelopes remain, protecting high-trust mail from eviction by lower-trust deposits.

How does BitChat prevent untrusted peers from depositing envelopes?

Untrusted peers—those without mutual vouch or verified signatures—are rejected before reaching the storage layer. The deposit method returns false immediately for untrusted tiers, and callers typically check trust status via SecureIdentityStateManager before attempting deposits. This prevents malicious actors from consuming any storage resources.

Can a verified peer upgrade to favorite tier to increase their quota?

Yes. When two peers mutually vouch for each other (tracked in ChatVouchCoordinator.swift), their trust relationship upgrades to favorite tier. Subsequent deposits use CourierDepositTier.favorite, which increases the per-depositor quota from 2 to 5 envelopes and removes the 20-envelope global pool restriction, while also granting eviction protection.

Where are the trust tiers defined and enforced in the codebase?

The CourierDepositTier enum is defined in bitchat/Services/Courier/CourierStore.swift, which also contains the deposit method that enforces quotas and eviction policies. Trust determination logic resides in bitchat/Identity/SecureIdentityStateManager.swift, while trust-change notifications emit from bitchat/ViewModels/ChatVouchCoordinator.swift.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →