← Back to home Case study · 2026

Wyvern

A privacy-first, Discord-style messenger with real end-to-end encryption.

RoleCo-built with Mattias Hansen
ContextProjet Transverse I · UNIGE
StackPython · Flask · Socket.IO · MySQL · Docker · Web Crypto
01 — Why

Context

On most mainstream platforms the content of your conversations passes through — or is stored on — servers that can read it, and signing up usually means handing over part of your real identity. Wyvern flips that: a server that routes and keeps messages without ever being able to read them, and sign-up with no verifiable personal data.

The trigger was concrete: the controversy around Discord's age-verification plans pushed us to imagine a community messenger built differently. Two inspirations — Discord for the familiar UX, and Mullvad VPN for identity, where a simple numeric code replaces your email and profile.

02 — What it does

Features

03 — The hard part

End-to-end encryption

Every message is encrypted in the browser with a hybrid scheme: EC-ElGamal over the secp256k1 curve to exchange a one-time key, then AES-256-GCM to encrypt the content.

The private key never leaves the client — it's stored encrypted with a key derived from your password (PBKDF2, 100,000 iterations) and only decrypted in memory for the session. The server stores and routes ciphertext it cannot read.

Database view showing encrypted message content
The same message in the database: unreadable ciphertext. The server never sees the text.
04 — Under the hood

Architecture

A dockerised client–server app: a Flask 3.1 backend with Flask-SocketIO (eventlet) and SQLAlchemy over MySQL 8, a vanilla-JavaScript front end talking REST + WebSockets, all orchestrated with Docker Compose.

Client-server Docker architecture diagram
Dockerised client–server architecture (Flask, MySQL, Socket.IO).
05 — Interface

A look at the app

06 — Outcome

Results

Wyvern works end to end. Every functional requirement is operational, real-time latency is imperceptible in testing, and the headline goal is verifiable: a message sent from the app is unreadable ciphertext in the database yet appears in clear for its recipient — while the server never sees the text.

07 — Transparency

Honest limits

Built for a course, with limits we own: the cryptography is hand-rolled for learning (not production-hardened, not constant-time, no forward secrecy), search runs client-side, and a member who joins a channel can't decrypt messages sent before they arrived.