Cryptography
Everything that travels through Velum is end-to-end encrypted with a hybrid scheme: classical (X25519) plus post-quantum (ML-KEM-768). If one of the two were broken, the other still protects the message.
Identity, wallet and devices
Everything starts from a 24-word recovery phrase (BIP-39, 256 bits). The word list follows the device language; Russian uses the English list because there is no official one.
seed = BIP39.mnemonicToSeed(phrase) 64 bytes
identity = HKDF-SHA512(seed, info = "velum/v2/identity") ed25519
wallet = HKDF-SHA512(seed, info = "m/44'/7420'/0'/0'/0'") ed25519
mailbox = HKDF-SHA512(seed, info = "velum/v2/mailbox") 32 B
- The identity signs your profile and your device list. Only your contacts know it (via QR code or link); it never goes to the network in plain text.
- The wallet signs transactions. It's a separate key so nobody can link chats and payments.
- Each device has its own random key that never leaves it: ed25519 (signing), X25519 and ML-KEM-768 (encryption).
Addresses are vel + base58 of the ed25519 public key (32 bytes). See Wallets and exchanges.
Device list
Each account shares with its contacts, inside encrypted profile messages, a list signed by the identity:
DeviceList = { identity, devices: [{ id, sign, x25519, kem, mailboxSeed, added, name }], ts, sig }
The list is never published on the chain. It allows up to 5 devices. Removing one means signing a new list without it and rotating the mailbox secret.
The hybrid envelope
For each recipient device:
eph = ephemeral X25519
(kemCt, kemSs) = ML-KEM-768.encapsulate(device.kem)
key = HKDF-SHA512(ikm = X25519(eph, device.x25519) ‖ kemSs,
salt = eph.pub ‖ kemCt,
info = "velum/v2/envelope", 32 bytes)
ciphertext = XChaCha20-Poly1305(key, 24 B nonce)
Format: [version 2][32 eph][1088 kemCt][24 nonce][ciphertext]. It's the same approach as Signal PQXDH and Apple PQ3: an attacker would have to break X25519 and ML-KEM-768 at the same time.
Sealed sender
From the outside, an envelope doesn't say who sent it. Inside are:
- The content (
Payload) signed by the sender's device key. - The sender's identity.
- A certificate: that identity's signature over that device.
So the recipient knows the message comes from that person, and nobody else can know it.
Groups
A group's content is encrypted once with a random key. That key is sealed (with the hybrid scheme) for each device of each member. Every copy looks like a one-to-one message: neither nodes nor an observer can tell it's a group or how many members it has.
Padding
Before splitting, the envelope is padded up to the next fixed bucket: 2 KB, 8 KB, 32 KB, 128 KB, 512 KB, 2 MB or 8 MB. A "hi" and a short voice note can weigh exactly the same. The real size travels inside, encrypted.
Forward secrecy through rotation
Each device rotates its X25519 + ML-KEM pair every 24 hours and announces the new one in its profile. It keeps the previous ones for 7 days to open late messages and then deletes them. If someone stole a device's key today, they couldn't open messages older than a week.
The full triple ratchet (per-message forward secrecy) is on the roadmap.
What attestation protects, and what it doesn't
The app asks Apple for proof (App Attest) that it is the original, unmodified app on a real iPhone. That proof protects the network against spam and reward theft. It is not what protects your messages: even if someone modifies the app, they can't read other people's messages. Cryptography guarantees that.
Algorithms
| Use | Algorithm |
|---|---|
| Signatures (identity, wallet, device, nodes) | ed25519 |
| Classical key agreement | X25519 |
| Post-quantum encapsulation | ML-KEM-768 (FIPS 203) |
| Key derivation | HKDF-SHA512 |
| Authenticated encryption | XChaCha20-Poly1305 |
| Receipts | HMAC-SHA512 and SHA-512 |
| Recovery phrase | BIP-39, 24 words |
| Transaction IDs | SHA-256 of canonical JSON |