How to Verify a Contact's Safety Number
Learn how to verify a safety number to confirm your contact's encryption keys and block impersonation or man-in-the-middle attacks in secure messaging apps.
By The PrivacyPortal Team
To verify a safety number, you compare a short code derived from you and your contact's encryption keys through a separate, trusted channel — in person or over a call you know is genuine — and confirm the two codes match. Doing this once proves that your end-to-end-encrypted conversation is actually reaching the real person, and not an impostor quietly sitting in the middle.
It takes about a minute, and it closes the one gap that encryption alone cannot close on its own. Here is what a safety number is, why it matters, and exactly how to check it.
What is a safety number?
In any end-to-end-encrypted messenger, each person has a pair of cryptographic keys: a private key that never leaves their device, and a public key that their contacts use to encrypt messages to them. Encryption works because you hold your contact's correct public key.
A safety number — some apps call it a security code, a fingerprint, or a verification code — is a short, human-readable value calculated from both participants' public keys. Think of it as a fingerprint of the conversation. If you and your contact hold each other's genuine keys, both of your devices will independently produce the same safety number. If the numbers differ, something between you has changed the keys.
Because it is derived from both keys at once, a safety number is unique to that one pair of people. It is not secret — it is meant to be read aloud or shown as a QR code. Its whole job is to be compared.
Why verifying prevents impersonation
Encryption scrambles your messages so that anyone watching the network sees only ciphertext. But encryption says nothing about who holds the key on the other end. That is the job of verification.
The attack it defends against is a man-in-the-middle (MITM). Imagine an attacker — or a compromised or malicious server — hands you a public key they control instead of your contact's real one. Your app happily encrypts to that key. The attacker decrypts each message, reads it, re-encrypts it with your contact's real key, and passes it along. Both sides see a normal, "encrypted" chat while a third party reads everything.
Verifying the safety number defeats this. Since the code is calculated from the real keys, an attacker who swapped a key cannot make both sides show the same number. Confirming the match out of band — through a channel the attacker does not control — is what turns "encrypted" into "encrypted to the person I actually mean." This is the same authentication problem at the heart of end-to-end encryption: the math is only as trustworthy as the key you started with.
How to verify a safety number, step by step
The principle is identical across apps, even when the buttons are named differently.
1. Open the verification screen
Both of you open the security or verification screen for each other's contact. It usually lives under the contact's profile, encryption info, or safety-number menu.
2. Compare through a trusted channel
Do not rely on the app you are verifying — that is the very channel an attacker might control. Instead:
- Best: in person. Sit together, open the screen, and either read the digits or scan each other's QR code. Scanning automates the comparison and removes typos.
- Remote but acceptable: read the code aloud on a video or voice call where you clearly recognize the person's face and voice. Recognizing them is what makes the channel trustworthy.
- Avoid: confirming the number only through the same chat you are trying to verify.
3. Mark the contact as verified
Once the codes match, mark the contact verified. Most apps will then warn you if the underlying keys ever change, so you are alerted instead of silently exposed.
What each app calls it
The terminology varies, but the mechanism is the same. Here is how a few well-known apps handle it.
| App | What it's called | How you compare it |
|---|---|---|
| Signal | Safety number | A 60-digit number or a QR code scan; then mark as verified |
| Security code | A 60-digit number or QR code under a contact's encryption info | |
| Threema | Verification level | Scan a contact's QR code in person to reach the highest trust level |
| Telegram | Secret Chat key | Only opt-in one-to-one Secret Chats are end-to-end encrypted; compare the key image |
A note on that last row: Telegram's ordinary cloud chats are not end-to-end encrypted, so there is nothing to verify there — only its opt-in Secret Chats are, and those are where a comparable key check appears. WhatsApp and Signal encrypt message content by default, so verification is available for every conversation.
What a "safety number changed" warning means
Sooner or later you will see a notice that a contact's safety number has changed. It has two possible causes:
- Benign: your contact reinstalled the app, switched phones, or otherwise generated new keys. This is common and usually harmless.
- Suspicious: someone is attempting a key-substitution attack.
You cannot tell which from inside the app, so treat it the same way you did the first time: re-verify out of band before sending anything sensitive. A quick call to ask "did you just get a new phone?" resolves the vast majority of these warnings.
How this works in Graphite
Graphite approaches identity in a way that changes where verification sits. There is no phone number and no email, and there is no account on the server. Your identity is a keypair generated on your own device from a 12-word recovery phrase, so the thing that represents "you" to a contact is your public key itself — not a phone number that some server maps to a key.
Under the hood, messages are sealed with NaCl/libsodium X25519 sealed boxes, wrapped in a hybrid post-quantum layer (ML-KEM-768), and given forward secrecy through a Signal-style double ratchet. The no-logs relay only ever holds sealed ciphertext — it never sees your plaintext, your keys, or your recovery phrase — and traffic runs over Tor by default, which hides your IP and network.
That design removes the usual middle layer that key-substitution attacks target: there is no server-side directory quietly mapping a phone number to a key that could be swapped without your knowledge. This is a real structural advantage over models that depend on trusting a phone-number-to-key lookup, and it is closely related to why metadata leaks so much elsewhere — see does Signal collect metadata for that side of the story.
Even so, the core discipline of secure messaging still applies to every tool, Graphite included: whenever you obtain a contact's key over any network, confirming their identity out of band is what makes the encryption trustworthy. Treat a first conversation with a new contact the way you would a safety-number check in any serious end-to-end-encrypted app — confirm you are talking to who you think you are before sharing anything sensitive. For the bigger picture of how these pieces fit together, our guide to the encrypted messenger walks through the full model.
Verify once, message with confidence
A safety number check is one of the highest-value minutes you can spend on your privacy: it upgrades "no one on the wire can read this" to "and it is reaching the right person." Do it in person when you can, over a recognizable call when you cannot, and re-verify whenever the number changes.
Want a messenger built on this mindset from the ground up — no phone number, no email, and no logs? Graphite is free and in public beta on Windows, Android, and the web. Try it at graphite.chat.