Criptografía
Todo lo que viaja por Velum está cifrado de extremo a extremo con un esquema híbrido: clásico (X25519) más poscuántico (ML-KEM-768). Si uno de los dos cayera, el otro sigue protegiendo el mensaje.
Identidad, cartera y dispositivos
Todo nace de una frase de recuperación de 24 palabras (BIP-39, 256 bits). La lista de palabras sigue el idioma del dispositivo; el ruso usa la inglesa porque no hay lista oficial.
semilla = BIP39.mnemonicToSeed(frase) 64 bytes
identidad = HKDF-SHA512(semilla, info = "velum/v2/identity") ed25519
cartera = HKDF-SHA512(semilla, info = "m/44'/7420'/0'/0'/0'") ed25519
buzón = HKDF-SHA512(semilla, info = "velum/v2/mailbox") 32 B
- La identidad firma tu perfil y tu lista de dispositivos. Solo la conocen tus contactos (por QR o enlace); nunca va en claro a la red.
- La cartera firma transacciones. Es otra clave para que nadie una chats y pagos.
- Cada dispositivo tiene su clave aleatoria, que nunca sale de él: ed25519 (firma), X25519 y ML-KEM-768 (cifrado).
Las direcciones son vel + base58 de la clave pública ed25519 (32 bytes). Ver Carteras y exchanges.
Lista de dispositivos
Cada cuenta publica a sus contactos, dentro de mensajes cifrados de tipo profile, una lista firmada por la identidad:
DeviceList = { identity, devices: [{ id, sign, x25519, kem, mailboxSeed, added, name }], ts, sig }
La lista nunca se publica en la cadena. Admite hasta 5 dispositivos. Al expulsar uno se firma una lista nueva sin él y se rota el secreto de buzón.
El sobre híbrido
Para cada dispositivo destinatario:
eph = X25519 efímera
(kemCt, kemSs) = ML-KEM-768.encapsulate(dispositivo.kem)
clave = HKDF-SHA512(ikm = X25519(eph, dispositivo.x25519) ‖ kemSs,
salt = eph.pub ‖ kemCt,
info = "velum/v2/envelope", 32 bytes)
cifrado = XChaCha20-Poly1305(clave, nonce de 24 B)
Formato: [versión 2][32 eph][1088 kemCt][24 nonce][texto cifrado]. Es el mismo enfoque que Signal PQXDH y Apple PQ3: un atacante tendría que romper a la vez X25519 y ML-KEM-768.
Remitente sellado
Por fuera, un sobre no dice quién lo manda. Dentro va:
- El contenido (
Payload) firmado por la clave de dispositivo de quien envía. - La identidad de quien envía.
- Un certificado: la firma de esa identidad sobre ese dispositivo.
Así el receptor sabe que el mensaje viene de esa persona, y nadie más puede saberlo.
Grupos
El contenido de un grupo se cifra una vez con una clave aleatoria. Esa clave se sella (con el esquema híbrido) para cada dispositivo de cada miembro. Cada copia parece un mensaje uno a uno: ni los nodos ni un observador pueden saber que es un grupo ni cuántos miembros tiene.
Relleno
Antes de trocearlo, el sobre se rellena hasta el siguiente cubo fijo: 2 KB, 8 KB, 32 KB, 128 KB, 512 KB, 2 MB u 8 MB. Un «hola» y una nota de voz corta pueden pesar exactamente lo mismo. El tamaño real va dentro, cifrado.
Secreto hacia delante por rotación
Cada dispositivo rota su par X25519 + ML-KEM cada 24 horas y anuncia el nuevo en su perfil. Conserva los anteriores 7 días para abrir mensajes rezagados y después los borra. Si alguien robara hoy la clave de un dispositivo, no podría abrir mensajes de hace más de una semana.
El triple ratchet completo (secreto hacia delante por mensaje) está en la hoja de ruta.
Qué protege la atestación y qué no
La app pide a Apple una prueba (App Attest) de que es la app original sin modificar en un iPhone real. Esa prueba protege a la red contra el spam y el robo de recompensas. No es lo que protege tus mensajes: aunque alguien modifique la app, no puede leer mensajes ajenos. Eso lo garantiza la criptografía.
Algoritmos
| Uso | Algoritmo |
|---|---|
| Firmas (identidad, cartera, dispositivo, nodos) | ed25519 |
| Acuerdo de clave clásico | X25519 |
| Encapsulado poscuántico | ML-KEM-768 (FIPS 203) |
| Derivación de claves | HKDF-SHA512 |
| Cifrado autenticado | XChaCha20-Poly1305 |
| Recibos | HMAC-SHA512 y SHA-512 |
| Frase de recuperación | BIP-39, 24 palabras |
| Identificadores de transacción | SHA-256 de JSON canónico |