Blind Drops Protocol

Post-quantum encrypted CSR transport for zero-knowledge certificate requests.

Problem

Traditional certificate enrollment requires a pre-existing trust relationship. The user must already have a way to securely transmit their CSR to the CA. In many environments — especially air-gapped or high-security contexts — this chicken-and-egg problem is solved manually (USB sticks, in-person delivery).

Blind Drops solve this: they let a user encrypt a CSR so that only the Authority can read it, even if every relay in between is compromised.

Design Goals

Protocol Flow

Step 1: Client Creates Drop (Passport)

  1. Passport loads the Authority's Kyber-1024 public key (transport.pub).
  2. Passport calls Encapsulate() on the public key, producing:
    • A ciphertext (1568 bytes) — only the Authority's private key can decode this.
    • A shared secret (32 bytes) — known to both sides after decapsulation.
  3. The shared secret is fed into Blake2b-256 to derive a 256-bit AES key.
  4. The CSR is encrypted with AES-256-GCM using a random 12-byte nonce.
  5. The drop file is assembled:
    [Header: "TRINITY-DROP-V1\n"] || [Kyber Ciphertext] || [Nonce] || [Encrypted CSR]
  6. The shared secret is saved to the Passport vault (needed to decrypt the response later).

Step 2: Drop is Relayed

The encrypted drop file is transmitted to the Authority via any channel:

Zero Knowledge: The relay stores the encrypted blob verbatim. It has no way to decrypt, inspect, or modify the CSR.

Step 3: Authority Unpacks Drop

  1. The Authority loads its Kyber-1024 private key (transport.key).
  2. It calls Decapsulate() on the ciphertext to recover the shared secret.
  3. The shared secret is fed into Blake2b-256 to derive the AES key.
  4. The encrypted CSR is decrypted with AES-256-GCM.
  5. The Authority reviews and signs the CSR, producing a certificate.

Step 4: Authority Seals Response

  1. Using the same shared secret (recovered from decapsulation), the Authority:
    • Derives a new AES key (Blake2b-256 of the shared secret).
    • Encrypts the signed certificate with AES-256-GCM and a new random nonce.
  2. The encrypted response is sent back through the same relay channel.

Step 5: Client Imports Response (Passport)

  1. Passport retrieves the saved shared secret from its vault.
  2. It derives the AES key and decrypts the response.
  3. The signed certificate is imported into the identity.
  4. The shared secret is permanently deleted from the vault.

Drop File Format

OffsetLengthField
016Header (TRINITY-DROP-V1\n)
161568Kyber-1024 Ciphertext
158412AES-GCM Nonce
1596VariableEncrypted CSR (AES-256-GCM)

Cryptographic Primitives

StepAlgorithmPurpose
Key ExchangeKyber-1024 (ML-KEM)Post-quantum key encapsulation
Key DerivationBlake2b-256Shared secret → AES key
EncryptionAES-256-GCMAuthenticated encryption of CSR/certificate

Security Properties

Breaking Change: The upgrade from Kyber-768 to Kyber-1024 means old transport.pub / transport.key files generated with Kyber-768 are incompatible. Re-run trinity init to generate new keys.