Ed25519 — who you are
The long-term signing key. Its public half goes into the invite, the private half never leaves the device.
Security
End-to-end encryption is not a checkbox in the interface: it is a specific envelope, a fixed order of checks and a list of assumptions. Here is what the project does, what an intermediary sees and where the guarantees end.
The app and the relay are open source: there is more to check than this page.
Every message gets its own key, and the authentication tag catches tampering before decryption.
Each message uses a fresh X25519 pair. Two identical texts look like two unrelated byte strings.
The envelope is signed with the sender long-term key: text, recipient and time cannot be swapped.
A node stores encrypted envelopes and metadata only. It cannot decrypt them.
Security is always a list of whom and what we protect against. This is the honest boundary.
An ISP, a Wi-Fi operator or a relay owner sees ciphertext and header fields only.
The Ed25519 signature and the envelope id prevent changes to the text, the recipient or the time on the way.
chainLink binds messages into a directed chain: inserting or reordering an envelope cannot go unnoticed.
There are no accounts: a password or an email cannot be stolen because neither exists.
Even a full dump of a node does not reveal conversations — it holds no recipient private keys.
Anyone with access to an unlocked phone or to the app files sees the keys and the conversation.
A relay and the network see who sent what, when and how much. This is not hidden, only minimised.
The other side reads the message legitimately. A screenshot or a forward is outside the encrypted zone.
If an attacker swaps the keys in an invite, they become the conversation partner. Compare keys over another channel.
A relay or the network can delay or drop an envelope. Delivery stays best-effort.
One envelope, one recipient. Inside there is only ciphertext, a signature and the fields needed to verify and deliver it.
envelope.json
id
SHA-256 over the sender, the recipient, the ciphertext, the time and chainLink.
senderPubKey
The sender long-term Ed25519 key. The same key verifies the signature.
recipientPubKey
The recipient long-term X25519 key. No other device can decrypt the envelope.
timestamp
UTC creation time. A timestamp too far in the future is dropped: the tolerance is 5 minutes.
ciphertext
AES-256-GCM: cipher || mac || nonce, base64 encoded. There is no plaintext here.
ephemeralPubKey
The public half of the X25519 pair created for this message only.
signature
Ed25519 over the id, the time, the ciphertext and chainLink. Changing any field breaks it.
chainLink
The id of the previous envelope in this directed chain. Empty for the first message.
An envelope is accepted only after a fixed order of checks: frame size → clock → signature → id → duplicate → decryption. Anything that fails is dropped without logging.
Five steps, each with its own area of responsibility.
The sender creates an X25519 pair and computes a shared secret with the recipient long-term key.
HKDF turns the shared secret into an AES-256-GCM key. No two messages share a key.
AES-256-GCM with a 12-byte nonce returns the ciphertext and a 16-byte authentication tag.
Ed25519 signs the id, the time, the ciphertext and chainLink with the sender long-term key.
Clock first, then the signature, the id, duplicates and only then decryption. A failure is never retried.
Limits are part of the model: a frame up to 256 KiB, plaintext up to 4 KiB, future time no more than 5 minutes. This protects against memory exhaustion and floods.
A relay is an honest but curious intermediary. It must not be able to read conversations, and it cannot.
Public keys are pseudonyms, not names. But frequency and timing still reveal a lot: that is metadata, and it stays visible.
A Soty identity is two key pairs on the device, not a record on a server.
The long-term signing key. Its public half goes into the invite, the private half never leaves the device.
The key envelopes are encrypted to. The other side needs the public half; the private half is yours alone.
History and keys do not sync between devices. A new phone starts with a new identity.
Conversations live for 30 days by default. You can pick 7, 90, 180 or 365 days, or keep them forever.
A password of 6 characters or more is stored as PBKDF2-HMAC-SHA256 with 210,000 iterations, plus fingerprint unlock.
Important: seed keys sit in local SQLite in plain form. This is a documented residual risk: with full access to the app files the keys can be extracted. For higher requirements use a dedicated device and app lock.
No system protects against everything. These limits are better known before than after.
The code is open, but the project does not claim an external audit. This page is not a substitute for one.
One-off keys protect messages from each other, but the recipient long-term X25519 key decrypts everything addressed to it.
Public keys are stable and a relay sees network addresses. Soty hides the text, not the fact of a conversation.
Losing the device means losing the keys and the history. There is no key export and no cloud backup.
Sources, protocol and builds are open. Start with the install, then verify the details in the code.