Browse Questions
  • They test different layers of the app and run at different speeds.
  • AsyncStream converts callback or delegate-based event sources into an AsyncSequence you can iterate over with for await.
  • TSCellSeal(key:) uses the bytes you supply directly as the symmetric key, while TSCellSeal(passphrase:) runs a human-typed string through a deliberately slow key derivation function first.
  • Prefer composition (a type holds/uses other types to get behavior) when: - The relationship is "has-a" rather than "is-a" (a Car has an Engine, it isn't an Engine) - You need to mix behaviors from…

Answer: TSCellSeal(key:) uses the bytes you supply directly as the symmetric key, while TSCellSeal(passphrase:) runs a human-typed string through a deliberately slow key derivation function first. They produce incompatible ciphertexts and are not interchangeable.

Use the key initialiser for machine-generated keys — high entropy, so a fast path is safe. Use the passphrase initialiser only for values a person types, such as a PIN or password, where the KDF's cost is what makes brute-forcing expensive. Passing a user's password to init(key:) is a real vulnerability: it makes the low-entropy secret directly guessable.

Code Example:

// Machine-generated key — from TSGenerateSymmetricKey() or the Keychain.
let byKey = TSCellSeal(key: TSGenerateSymmetricKey()!)!

// Human-supplied secret — KDF applied internally, slow by design.
let byPassphrase = TSCellSeal(passphrase: userEnteredPIN)!
let sealed = try byPassphrase.encrypt(secret.data(using: .utf8)!)

// Decrypting with the wrong constructor throws — the formats differ.

Key Points:

  • Never hand a user password to init(key:).
  • Passphrase mode is intentionally slow; do not call it in a tight loop or on the main thread.
  • Ciphertext from one initialiser cannot be read by the other.