Download PairCrypt
What is PairCrypt?
PairCrypt is a privacy-focused communication service designed to let you communicate without requiring personal account registration or revealing the contents of your private conversations. When used with the built-in Tor network enabled, PairCrypt also helps prevent the disclosure of your IP location.
Who Funds PairCrypt & Why Use Subscriptions?
PairCrypt is independently built and funded through user subscriptions.
Subscriptions help support our real-time relay infrastructure, cloud operating costs, and ongoing security maintenance and development.
We don't sell user data or run tracking-based advertising. Our subscription-based model is designed to support PairCrypt without relying on advertising revenue or data monetization.
We believe privacy software should put users' privacy first. By funding PairCrypt directly through subscriptions, we aim to keep our business incentives aligned with building and maintaining a private, secure communication service.
Protocol Architecture Lifecycle
sequenceDiagram
autonumber
participant Marry as Marry
participant Store as Apple / Google Play Store
participant Cloud as Server
participant David as David
Note over Marry: 1. Launch App & Anonymous Identity Generation
Marry->>Marry: Generate PairCrypt ID (quota_id_marry_9982) locally
Marry->>Marry: Store PairCrypt ID in Device (OS Secure Storage)
Note over Marry, Cloud: 2. Privacy-Preserving Subscription (Two-Signal VOPRF)
Marry->>Store: Buy Subscription / Pay via App Store / Google Play
Store-->>Marry: Return Store Purchase Receipt
Note over Marry: Signal 1: Receipt Verification & Voucher Unblinding
Marry->>Marry: Generate secret blinding factor (r) & random voucher (v) in RAM
Marry->>Marry: Compute Blinded Point P = r * HashToCurveP256(v || ":" || month_anchor)
Marry->>Cloud: Send P + Store Receipt (NO PairCrypt ID sent)
Cloud->>Store: Verify Receipt with Apple/Google
Store-->>Cloud: Receipt Valid
Cloud->>Cloud: Sign Blinded Point Q = d * P (using server private key d)
Cloud-->>Marry: Return Signed Point Q + Authoritative server month_anchor
Marry->>Marry: Unblind Q using r^-1 ➔ Saves VOPRF Signature S = r^-1 * Q and server-authoritative month_anchor
Note over Marry: Signal 2: Voucher Redemption & Activation (Tap ACTIVATE)
Marry->>Cloud: Send Unblinded Voucher (v, S, month_anchor) + PoW Nonce + PairCrypt ID (NO Receipt sent)
Cloud->>Cloud: Verify PoW Nonce & VOPRF: d * HashToCurveP256(v || ":" || month_anchor) == S
Cloud->>Cloud: Grant Active Status to (quota_id_marry_9982) in subscription_entitlements
Cloud-->>Marry: Confirmation ➔ PairCrypt ID becomes Premium Active!
Note over Marry: 3. Create Room "Secret HQ", Relay Secret & Mask ID Generation
Marry->>Marry: Generate (masterkey1) = 8F3C19E4...
Marry->>Marry: Derive relaySecret = HKDF-SHA256(masterkey1, "paircrypt-relay-v1")
Marry->>Marry: Compute Mask ID_Marry = SHA256(quota_id_marry + relaySecret)
Marry->>Marry: Compute Header x-relay-auth = SHA256(relaySecret)
Marry->>Cloud: Call RPC publish_room(p_quota_id = quota_id_marry, Mask ID, x-relay-auth)
Cloud->>Cloud: Lookup quota_id_marry in subscription_entitlements ➔ Active!
Cloud-->>Marry: Room Created & Connected
Note over Marry: 4. Send Message "Hello World!"
Marry->>Marry: Encrypt "Hello World!" with (masterkey1) via AES-256-GCM
Marry->>Cloud: Broadcast Ciphertext payload to Channel_x99
Note over Cloud: The relay receives encrypted message payloads and processes limited routing metadata (room ID, sequence number) needed for delivery. It does not possess the decryption keys.
Note over Marry, David: 5. Add Device & Join Code Exchange
Marry->>Marry: Generate (joinCode)K9X2M4P8Q7W1 ➔ Computes (hashedCode) = PBKDF2(joinCode, 15,000)
Marry->>Marry: Generate (marryPrivKey) & (marryPubKey) via X25519
Marry->>Marry: Encrypt (marryPubKey) using AES-256-GCM(key = PBKDF2(joinCode))
Marry->>Cloud: Publish (hashedCode) + Encrypted (marryPubKey)
David->>David: Generate PairCrypt ID (quota_id_david_4412) locally
David->>David: Install App & Type (joinCode) ➔ Computes (hashedCode)
David->>Cloud: Fetch & Decrypt (marryPubKey) using PBKDF2(joinCode)
David->>David: Generate (davidPrivKey) & (davidPubKey) via X25519
David->>Cloud: Send (davidPubKey) + HMAC Signature using (joinCode)
Note over Marry, David: 6. Key Exchange & (sharedSecret) Calculation
Cloud->>Marry: Relay (davidPubKey)
Cloud->>David: Relay (marryPubKey)
Marry->>Marry: MATH: X25519(marryPrivKey, davidPubKey) ➔ CREATES (sharedSecret)
David->>David: MATH: X25519(davidPrivKey, marryPubKey) ➔ CREATES (sharedSecret)
Note over Marry, David: Both devices compute identical 256-bit (sharedSecret) bound to this pairing session!
Note over Marry, David: 7. SAS Verification & Master Key Transfer
Marry->>Marry: Compute 6-digit (sasCode)481920 via PBKDF2(sharedSecret, 50,000)
David->>David: Compute 6-digit (sasCode)481920 via PBKDF2(sharedSecret, 50,000)
Note over Marry, David: Both screens display 6-digit "(sasCode)481920" ➔ Tap "CONFIRM MATCH"
Marry->>Marry: Package (masterkey1) encrypted using AES-256-GCM(key = sharedSecret)
Marry->>Cloud: Send Encrypted Key Bundle
Cloud->>David: Relay Encrypted Key Bundle
David->>David: Decrypt (masterkey1) using (sharedSecret) & store in Device
Marry->>Marry: DELETE (sharedSecret) from RAM
David->>David: DELETE (sharedSecret) from RAM
Note over Marry, David: 8. History Sync (Transfer Past Messages)
David->>Cloud: Send history_request (maxSeq=0, isInvitee=true)
Cloud->>Marry: Relay history_request
Marry->>Marry: Check myMaxSeq > 0 ➔ Becomes DONOR
Marry->>Cloud: Send history_offer
Cloud->>David: Relay history_offer
David->>Cloud: Send history_accept
Cloud->>Marry: Relay history_accept
Marry->>Cloud: Send Encrypted History Chunks from local vault
Cloud->>David: Relay History Chunks
David->>David: Decrypt past messages using (masterkey1) & render on screen
Note over Marry, David: 9. Kick Device & Access Revocation
Marry->>Cloud: Broadcast Kick Signal + RPC reset_room_after_kick
Cloud->>Cloud: Server invalidates old x-relay-auth & resets room authorization
Cloud->>David: Relay Kick Signal
David->>David: Client wipes room & deletes (masterkey1) from local vault
Marry->>Marry: Retires (masterkey1) [is_active=0] locally (retained to read past history)
Marry->>Marry: Generates NEW active (masterkey2) for all future messages
Note over Marry, David: David's room access is revoked on the relay. The server rejects his previous authorization, and future messages are protected by masterkey2. Previously received messages on David's device cannot be remotely erased if his client is modified.