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