Cryptography

How we protect your messages

Hushwire implements the Signal Protocol from scratch in Rust. We follow Signal's published specifications, but we make deliberate choices about primitives, constructions, and post-quantum protection. This page explains what those choices are and what they mean for you.

Contents

The foundation: Signal Protocol

Hushwire's encryption is built on the Signal Protocol, the same protocol used by Signal, WhatsApp, and Google Messages. It provides end-to-end encryption, forward secrecy, and post-compromise security for every conversation.

We implement five of Signal's published specifications:

The protocol design is well-studied, peer-reviewed, and has withstood years of cryptographic scrutiny. We did not design a new protocol. We implemented an existing one, with specific improvements described below.

Why we wrote our own implementation

"Never write your own crypto" is a tenet we live by. We evaluated Signal's open-source libsignal library seriously, because using battle-tested code is almost always the right call. But libsignal could not give us what we needed:

So we did the thing you are not supposed to do, carefully. The implementation is written from Signal's published specifications, diverging only where documented. Every divergence is cataloged with rationale in a technical register designed for security researchers and auditors. We did not invent a new protocol. We implemented an existing one, with specific improvements, and we wrote down every place where we did something different and why.

Post-quantum protection

Quantum computers do not yet exist at a scale that threatens encryption. But encrypted traffic captured today could be stored and decrypted later when they do. This is called a "harvest now, decrypt later" attack.

Signal addresses this by adding a quantum-resistant key exchange (ML-KEM, formerly known as Kyber) to the initial handshake when two people start a conversation. If a quantum computer later tries to break that handshake, the ML-KEM component keeps it safe.

Hushwire goes further. We add ML-KEM protection at every ratchet step, not just the initial handshake. Every time the conversation direction changes (you send, they reply), fresh quantum-resistant key material is mixed into the encryption keys.

What this means for you

Bandwidth cost

Post-quantum keys are larger than classical keys. Each direction change in a conversation adds about 2.3 KB of quantum-resistant material. In a typical back-and-forth conversation, this means a few extra kilobytes per message. For most connections, this is imperceptible. On very constrained networks, you may notice slightly larger message sizes.

Metadata protection

The content of your messages is always encrypted. But metadata -- who is talking to whom, when, how often -- can reveal just as much. Hushwire applies several layers of metadata protection:

Encrypted message headers

In the standard Signal protocol, message headers (which contain key exchange material) can be sent unencrypted. A network observer can use these headers to track conversations and correlate messages.

In Hushwire, message headers are always encrypted. An observer on the network sees ciphertext, not key exchange parameters. They cannot determine which conversation a message belongs to or track how encryption keys are evolving.

This also matters for the continuous post-quantum ratchet: the quantum-resistant key material travels inside the encrypted header, so an attacker cannot selectively strip it out to force a downgrade to classical-only encryption.

Sealed sender

When you send a direct message, Hushwire uses a two-layer encryption scheme so that the server delivers the message without knowing who sent it. The recipient's device decrypts the sender identity locally. The server sees only an opaque blob addressed to a recipient.

Encrypted community metadata

Community names, descriptions, and avatars are encrypted before they are uploaded to the server. The server stores ciphertext it cannot read. Profile pictures are encrypted on your device before upload. Even the metadata about your community is opaque to the server.

Signed group messages

Just like Signal, every group message is wrapped in a signed envelope. The sender signs all fields -- sender identity, timestamp, and message content -- with their Ed25519 identity key. Recipients verify this signature before trusting any part of the message, including who sent it.

The server issues short-lived certificates (valid for 24 hours) that bind each user's identity to their signing key. Recipients check both the server's signature on the certificate and the sender's signature on the message. A forged message would require the victim's private identity key, which never leaves their device.

Each sender also has their own chain key for content encryption, distributed to other group members over individually encrypted sessions. There is no single shared group key -- compromising one member's chain key does not let an attacker impersonate anyone else.

What this means for you: no group member can send a message that appears to come from someone else. If your group has leaders or admins, their identity cannot be spoofed by other members.

Modern primitives

The Signal Protocol specification allows implementations to choose specific cryptographic building blocks. We chose modern, well-audited primitives that are safe by default on all hardware:

WhatSignalHushwire
Message encryption AES-256-CBC + HMAC XChaCha20-Poly1305
Identity keys Curve25519 + XEdDSA Ed25519 (standard)
Post-quantum ML-KEM-1024 (handshake) + ML-KEM-768 (continuous, via SPQR)2 ML-KEM-1024 (handshake) + ML-KEM-768 (continuous)
Header encryption Optional Always on
Group authentication Ed25519 signatures Ed25519 + HMAC

Why XChaCha20-Poly1305?

AES requires dedicated hardware instructions to run safely in constant time. Without them, AES implementations can leak information through timing differences. XChaCha20-Poly1305 runs in constant time on all hardware, needs no special CPU instructions, and has a large enough random nonce space (24 bytes) that accidental reuse is astronomically unlikely. It is the recommended AEAD in libsodium and is used by tools like age for file encryption3. WireGuard uses the closely related ChaCha20-Poly1305 (with a 96-bit nonce) for data packets; we chose the extended-nonce variant because a 24-byte random nonce makes accidental reuse a non-concern even at very high message volumes4.

Why Ed25519?

Signal uses Curve25519 as the canonical key format and constructs signatures on top via a scheme called XEdDSA. Hushwire uses standard Ed25519 keys directly. Ed25519 has broader library support, more extensive audit coverage, and is simpler. When we need to perform key agreement, we convert to the appropriate format using a well-defined mathematical mapping.

What we're honest about

We believe in telling you what we know and what we do not know.

The continuous post-quantum ratchet has no formal proof

The construction is simple and the informal security argument is straightforward: the quantum-resistant material is mixed into key derivation alongside the classical key exchange, and can only strengthen the result. But "informal" means a cryptographer has not written a formal proof, and automated verification tools have not confirmed it. Signal's alternative approach (the Triple Ratchet1, which adds SPQR to the existing Double Ratchet) has been formally verified with ProVerif, hax, and F*5.

We are seeking independent review. In the meantime, even in the worst case (the continuous post-quantum ratchet contributes nothing), you still have the same security as standard Signal Protocol with the initial post-quantum handshake.

This code has not been independently audited

The implementation follows Signal's published specifications, is tested extensively, and is designed for auditability. But it has not yet undergone a professional third-party security audit. This includes the continuous post-quantum ratchet, which is a new construction that has not been formally proven secure. We plan to commission an independent audit. When we do, the results will be published here.

Sealed sender has a metadata tradeoff

To prevent a specific attack where an adversary swaps the sender identity inside an encrypted envelope, we bind the sender's certificate to the message ciphertext. This binding differs from how Signal's sealed sender associates sender identity with the envelope6. The tradeoff is that the server can tell whether two sealed sender messages came from the same sender, without knowing who that sender is. This is a pseudonym, not an identity, but it is information that Signal's approach does not leak. We believe the integrity benefit outweighs this cost for most threat models.

Summary

The short version of what Hushwire's cryptography means for you:

ProtectionWhat it means
Signal Protocol Same proven protocol design used by Signal, WhatsApp, and Google Messages
Continuous post-quantum Quantum-resistant keys at every conversation turn, not just the first handshake
Encrypted headers Network observers cannot track conversations by watching key exchange patterns
Signed groups Every group message is signed with the sender's identity key, preventing impersonation
Modern ciphers XChaCha20-Poly1305 runs safely on all hardware, no special CPU instructions needed
Sealed sender The server delivers your DMs without knowing who sent them
Written in Rust Memory safety eliminates the most common class of security vulnerabilities

Source code and audit

The cryptographic library is called hushwire-crypto. The source code will be published as an open-source repository. When it is, a link will appear here.

A detailed technical document catalogs all 19 places where our implementation diverges from Signal's specifications. It includes source file references, security classifications, rationale, and known limitations. That document is written for security researchers and auditors and will be published alongside the source code.

If you are a security researcher and want early access to the source or the divergence register, email security@hushwire.io.

References

  1. Signal, "Signal Protocol and Post-Quantum Ratchets" (Oct 2025) — announces SPQR and the Triple Ratchet: https://signal.org/blog/spqr/. The ML-KEM Braid is a sub-component of SPQR, documented separately at https://signal.org/docs/specifications/mlkembraid/.
  2. PQXDH uses ML-KEM-1024 (the spec references CRYSTALS-KYBER-1024): https://signal.org/docs/specifications/pqxdh/. SPQR uses ML-KEM-768; see Signal's SPQR blog post (footnote 1), which references "this incremental version of ML-KEM 768" and an EK size of 1184 bytes (ML-KEM-768's public key length).
  3. libsodium documents XChaCha20-Poly1305 as its recommended AEAD construction: https://doc.libsodium.org/secret-key_cryptography/aead/chacha20-poly1305/xchacha20-poly1305_construction. The age file encryption tool uses ChaCha20-Poly1305 with a random nonce extension; spec at https://age-encryption.org/v1.
  4. WireGuard's protocol specification defines two AEAD primitives: ChaCha20-Poly1305 (96-bit nonce, RFC 7539) for transport data, and XChaCha20-Poly1305 (24-byte random nonce) for cookie reply packets under DoS load. See https://www.wireguard.com/protocol/.
  5. Formal verification of the Triple Ratchet is described in Signal's SPQR announcement (footnote 1), in the Eurocrypt 2025 paper at https://eprint.iacr.org/2025/078, and in the USENIX Security 2025 paper at https://www.usenix.org/system/files/usenixsecurity25-auerbach.pdf.
  6. Signal's sealed sender includes a server-issued sender certificate inside the encrypted envelope; see https://signal.org/blog/sealed-sender/. A detailed comparison with our binding approach is documented in our divergence register, available on request to security researchers.