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 protocols:

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. In the end we couldn't build on it, mainly for a licensing reason, plus a few technical ones:

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's original post-quantum design, PQXDH, adds 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 carries that protection through the whole conversation. We implement Signal's Triple Ratchet (the ML-KEM Braid, also called SPQR): fresh ML-KEM key material is streamed alongside your messages and folded into the encryption keys as the conversation goes on, not just at the initial handshake. A new quantum-resistant secret is mixed in periodically as you talk, so the ongoing conversation keeps being re-protected rather than relying on the one-time handshake alone.

What this means for you

The honest limits

Two caveats worth stating plainly. Because the quantum-resistant material travels in the open alongside each message, someone who controls your network can strip it out. They cannot read your messages or quietly weaken them -- if they tamper, the conversation simply stops working -- but they could use this to disrupt a connection. And the protection assumes your own device has not already been taken over. An attacker who has compromised your device and the keys on it could switch the quantum-resistant layer off, though by then they already hold everything it was protecting.

Bandwidth cost

Post-quantum keys are larger than classical keys. Rather than attaching all of that material to a single message, Hushwire streams it in small pieces spread across many messages, so each message carries only a few dozen extra bytes. A fresh quantum-resistant secret finishes arriving roughly every several dozen messages. For most connections this is imperceptible, and there is no single oversized message to slow things down on constrained networks.

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 protects metadata on two fronts:

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

Group messages use Signal's Sender Keys. Each member has their own encryption chain, distributed to the rest of the group over individually encrypted, authenticated sessions. There is no single shared group key, so compromising one member's keys never exposes anyone else's chain.

Every message is signed with the sender's Ed25519 signing key, and recipients verify that signature before trusting any part of the message. Because the signature is asymmetric, only the genuine sender can produce it, and that key is bound to the member through the authenticated channel used to distribute it. No other group member can forge a message that appears to come from someone else.

What this means for you: inside a group, identities cannot be spoofed. If your group has leaders or admins, no other member can post a message that looks like it came from them.

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, via SPQR)

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 protocol is proven; our implementation has not been audited

Hushwire's continuous post-quantum ratchet is Signal's Triple Ratchet1 (the ML-KEM Braid, SPQR) -- the same design that has been formally verified with ProVerif, hax, and F*5. That proof covers the protocol. It does not cover our code: we wrote our own clean-room implementation from Signal's published specification (we do not read or copy Signal's source, which is licensed differently from Hushwire), and that implementation has not yet been independently verified or audited. So the honest statement is "Hushwire implements Signal's formally-verified post-quantum ratchet," never "Hushwire is formally verified."

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 our implementation of the continuous post-quantum ratchet: the underlying protocol is Signal's formally-verified Triple Ratchet, but our clean-room code for it has not been independently reviewed. 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 refreshed as the conversation continues, not just the first handshake
Signed groups Every group message is signed with the sender's key, so members can't be impersonated
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, and it is open source. You can read every line at github.com/hushwire/hushwire-crypto.

A detailed technical document — the Signal specification divergence register — catalogs every place where our implementation diverges from Signal's specifications. It includes source file references, security classifications, rationale, and known limitations, and is written for security researchers and auditors.

The code has not yet undergone a professional third-party security audit. If you are a security researcher, find something, or want to discuss the implementation, 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.