Skip to content
For everyone and for engineers

Security

Your data, your device. Verifiable. Tacita's security story is built so the friendly version and the technical version describe the same thing — one in plain language, the other in named cryptographic primitives.

For everyone

Most privacy policies are a request to trust the vendor. Tacita is built so there is nothing to trust us with in the first place — and so a curious engineer can verify that by reading the same primitives a cryptographer would.

  • Your chats never leave your phone.

    The language model runs on your device. There is no server we forward your messages to, no remote inference endpoint, no cloud queue. When the app is offline, it still answers — because the model is already on the phone.

  • Encrypted with a key only you know.

    Your password derives the key that locks every chat, persona, note, and attachment on disk. We never see your password. If you forget it, no one — not us, not law enforcement, not the device manufacturer — can recover the vault. That is the trade-off, and it is intentional.

  • Secret vaults stay hidden.

    You can create a second vault that does not appear in the unlock screen. It opens only when you type its password directly. An observer holding your phone cannot tell whether a secret vault exists.

  • One purchase. No subscription. No account.

    Tacita is a one-time payment processed by the platform store. There is no account to create, no email to verify, no profile to delete. We could not email you if we wanted to.

What we defend against

Concrete threats first, the primitives that answer them second. If a row looks abstract, it is in the technical section below with its name, library, and notes.

  • Someone steals or seizes your phone.

    Without your password, the vault is a wall of authenticated ciphertext. Auto-lock fires the instant you switch apps; the master key lives in RAM only and is wiped on lock.

  • Forensic recovery tool runs against the device storage.

    Every chat, persona, blob, and setting on disk is AES-256-GCM under a key the device cannot produce without your password. Deleted records pass through a multi-stage overwrite before unlink.

  • Hostile Wi-Fi or DNS hijack on the Bridge link.

    The Bridge transport is mutually authenticated and encrypted before any payload byte crosses the wire. A passive observer on the LAN cannot complete the handshake without the QR-derived pre-shared key.

  • Cold-boot or memory dump on an unlocked but idle app.

    While idle, the master key and the Bridge identity key are wrapped under a hardware-bound key (iOS Keychain access-controlled, Android StrongBox / TEE).

  • Modified app build pretending to be Tacita.

    Opt-in platform attestation in Bridge settings refuses to pair with a phone whose Play Integrity / App Attest response is missing or invalid. The shipping binary is also reproducible and signed: anyone can rebuild from source and verify the SHA-256.

  • Harvest-now-decrypt-later quantum adversary.

    Post-quantum hybrid Bridge transport (X25519 + ML-KEM-768) is staged for the next release wave; the wire format already reserves the hybrid byte so the upgrade does not break paired devices.

What Tacita honestly does not defend against:

  • A compromised Secure Enclave or StrongBox firmware (accepted residual; this is below the app boundary).
  • Userland malware on the device while the vault is already unlocked.
  • Coerced biometric unlock for non-secret vaults.
  • A guessable password. No client-side encryption can compensate for one.

For the technical reader

The list below names every cryptographic primitive Tacita ships in the current binary, with one paragraph on why we picked it. No analogies, no "military-grade" claims. If a primitive does not yet ship, it is labelled coming.

  • Argon2id (m = 64 MiB, t = 3, p = 4)

    Memory-hard password-to-key derivation. Recommended by NIST and OWASP over older constructions like PBKDF2 because it is hostile to GPU and ASIC brute-force. Calibrated to roughly 600–850 ms on a mid-range phone, which is the practical ceiling for unlock latency on a thermally-throttled mobile CPU.

  • AES-256-GCM

    Authenticated encryption for every persisted file: chats, personas, settings, blobs, memory records. 12-byte random nonce per record, 16-byte authentication tag, no AAD. Decryption is preceded by a versioned envelope header so the format can evolve without a one-shot migration.

  • Noise Protocol IK + PSK2 (X25519 + ChaCha20-Poly1305)

    Mutually-authenticated transport for the optional phone-to-desktop Bridge. The pre-shared key is derived from the QR pairing payload, so a passive observer on the same network cannot complete the handshake. Every session uses fresh ephemeral keys for forward secrecy. The Noise Protocol Framework has been independently analysed (Kobeissi, Bhargavan and Blanchet, IEEE EuroS&P 2019).

  • iOS Keychain (access-controlled) and Android StrongBox key wrapping

    While the app is idle, the unlocked master key and the Bridge identity key are wrapped under a hardware-bound key. A cold-boot memory dump on a locked device cannot lift them. Honest scope: the iOS Secure Enclave does not implement AES itself, so the keychain attribute kSecAttrAccessibleWhenUnlockedThisDeviceOnly gates release while the actual AES happens in the kernel. On Android the wrapping key is generated inside StrongBox or TEE and never leaves it.

  • HKDF-SHA-256 with versioned info strings

    Every derived key — per-record, per-session, per-purpose — is produced by HKDF with a context-specific info string. The context prevents the same input from yielding the same key in two different roles, which is what closes the door on cross-protocol attacks.

  • Constant-time comparisons for security-sensitive material

    MACs, AEAD tags, attestation responses and pre-shared-key proofs are compared in constant time. A repository-wide lint refuses to ship a short-circuiting byte comparison on this kind of material — the check runs in the release gate and fails the build if it finds one.

  • CycloneDX 1.5 software bill of materials (signing: minisign — coming)

    Every shipping platform publishes a CycloneDX 1.5 software bill of materials generated from the resolved lock files. The artifacts are listed on /sbom with a SHA-256 per file. Detached minisign signatures and the public verification key bootstrap with the first official release; until then, in-transit integrity is verifiable with sha256sum against the hashes published on /sbom. A fully reproducible-build pipeline (deterministic rebuild from a clean Docker image) is the next milestone on this front.

  • Bridge attestation signal (Play Integrity and App Attest, opt-in)

    When the user enables "Require attested phones" in the Bridge settings, the desktop companion refuses to pair with a phone whose platform attestation is missing or invalid. By default this is off, because forcing attestation would lock out users on rooted phones, custom ROMs, or non-Google-Services devices.

  • Post-quantum hybrid Bridge transport (X25519 + ML-KEM-768) — coming

    To defend against the harvest-now-decrypt-later threat, the Bridge handshake will mix a post-quantum key encapsulation mechanism (ML-KEM-768, also known as Kyber768) alongside X25519. The wire format already reserves the hybrid byte; the FFI surface is staged behind a feature flag pending the cross-platform liboqs build.

Verifying the binary you downloaded

The current verification surface has two layers. What ships today is the dependency manifest itself — a CycloneDX 1.5 software bill of materials for every Tacita platform, listed at /sbom with a SHA-256 per file. Detached minisign signatures and the public verification key bootstrap with the first official release; the steps that depend on them are labelled below.

  1. Inspect the dependency manifest. Fetch the CycloneDX 1.5 SBOM for the platform you care about from /sbom — one document per platform (mobile, desktop core, desktop UI, this site). Each document lists every resolved dependency by name, version, package URL, source URL, and content SHA-256. The artifacts load directly into Dependency-Track, Grype, OSV-Scanner, or any CycloneDX consumer.
  2. Verify the SBOM's in-transit integrity. Compare the SHA-256 of the file you downloaded against the value listed beside it on /sbom (also in /sbom/index.json):
    sha256sum tacita-mobile.cdx.json
    # compare against the value listed at /sbom
  3. Verify the SBOM signature (coming). Detached minisign signatures (*.cdx.json.minisig) and the public key (tacita_sbom_pub.minisign) bootstrap with the first official release. The verifier will then be:
    minisign -V -p tacita_sbom_pub.minisign \
      -m tacita-mobile.cdx.json
    A clean exit will mean the SBOM was signed by the offline Tacita release key, which never touches a CI machine.
  4. Verify the binary against the per-release manifest (coming). Each release will publish a manifest listing the SHA-256 of every shipping binary, signed with the same key, and a sha256sum of the APK / IPA / desktop bundle will match the manifest entry.

A fully containerised reproducible-build pipeline (deterministic rebuild from a clean Docker image) is the next milestone on this front. Where this page promises a future step it says so explicitly; everything else on this page is verifiable against the current binary.

Disclosure and audits

Reports are read by a human at [email protected] — plain text or PGP-encrypted both fine. The human-readable disclosure policy is at /security/policy: 72-hour acknowledgement, 7-day first technical reply, 90-day coordinated disclosure, opt-in hall-of-fame credit, no legal threats for good-faith research. The machine-readable disclosure metadata follows RFC 9116 at /.well-known/security.txt.

Tacita has not yet undergone an external security audit. A scoped audit (cryptography + Bridge transport) is planned post-launch and will be funded out of Pro revenue. When it ships, the scope and the full report will be published on this page.

Where the app says the same thing

The in-app screens — Settings → About → Privacy Policy, and the Licenses screen — list the same primitives and the same library versions as this page. If the marketing site and the in-app text ever disagree, the in-app text is the ground truth (it is bound to the version of the binary you installed) and this page will be corrected in the next release.

Related: privacy architecture in detail, glossary of cryptographic terms, privacy policy.