WIGGWIGG Security Whitepaper
Version: 1.1 (draft) · Date: 2026-07
WIGGWIGG is a privacy-first phone-number and identity product. This document describes, in technical detail, how we protect your data: what we cannot read, what we can read and why, the cryptography we use, and where our guarantees end. It is written for a skeptical, technical reader.
Our cryptographic core is open source at github.com/WiggWiggDev/crypto (the
@wiggwigg/crypto package): the key-derivation, sealing, and signing primitives
this document describes are auditable independently of the closed application.
1. Summary and stance
- Zero-knowledge by design. Your password, vault entries, identities, contacts, and message content are encrypted on your device with keys we never hold. We cannot read them, and we cannot be compelled to produce a key we don’t have.
- Open-core, not “open source.” We open-sourced the cryptographic core so you can audit how keys and data are protected. The rest of the application (the operational and abuse-defense surfaces) is closed. We never imply otherwise.
- The edges. Phone numbers, emergency (E911) addresses, and routing metadata are server-readable because phone service requires it. We are not end-to-end-encrypted in transit (the phone network predates that). We do not yet have forward secrecy or post-quantum protection. Those limits are stated in sections 10 and 11.
- Self-attested today, externally audited later. This document is backed by open source code and a published vulnerability-disclosure policy. A third-party cryptographic and application audit is planned; we will publish it when complete and will not claim it before then.
2. Threat model and trust boundaries
We design against a fully malicious server, not merely an honest-but-curious one: assume our infrastructure may be compromised, subpoenaed, or operated by someone who should not see your data, and that it may actively lie to your device rather than just watch. Under that assumption, your zero-knowledge data stays unreadable because the keys live on your device. That is the threat model the 2026 USENIX Security cryptographic analysis of password managers argues is the correct one (Zero Knowledge (About) Encryption, Scarlata et al.), and the one we hold ourselves to; the residuals we still carry under it are stated in section 10, not left out.
| Boundary | What we assume | What it can see |
|---|---|---|
| Your device | Trusted; client-side crypto runs here | Everything you store (it holds your keys) |
| Your password / recovery phrase | Secret, known only to you | Nothing leaves the device |
| WIGGWIGG servers | May be compromised, compelled, or malicious | Server-encrypted operational data (section 4); never ZK data |
| Database | Protected by row-level security and triggers | Ciphertext only, for ZK data |
| Telecom carrier (Telnyx) | A “dumb pipe” that learns only what routing requires | Call/SMS metadata and content in transit (like all phone service) |
| Payment processors (Stripe, Blockonomics) | Data-minimized | Card-billing essentials, or a Bitcoin address and amount; never your vault or identities |
We do not defend against a compromised endpoint (malware on your own device, or a malicious browser extension), nor against metadata inherent to placing a phone call or SMS through the public network. See section 10.
3. Cryptographic architecture
All primitives below come from audited libraries
(@noble/curves,
@noble/hashes,
@scure/bip39). We do not roll our own.
- Key derivation: your password is stretched with Argon2id (128 MiB memory, 3 iterations). It is memory-hard and resistant to GPU/ASIC brute-force. The same parameters are byte-for-byte identical across web and mobile so your keys match on every device.
- Vault-key indirection: the password-derived master key wraps a separate, per-account vault key, and your data is encrypted under the vault key. Changing your password re-wraps the vault key only; it never re-encrypts your data.
- Symmetric encryption: AES-256-GCM (authenticated) for vault entries, identities, contacts, message content, and server-side operational fields.
- Public-key sealing: inbound message content is encrypted with AES-256-GCM under a one-time key, which is itself sealed to your device’s X25519 public key (X25519-ECDH, HKDF-SHA256, XChaCha20-Poly1305: a libsodium-style sealed box). If your device has no X25519 key on file yet, the session key is wrapped with RSA-2048-OAEP instead, the legacy scheme; each blob records which was used. Both are zero-knowledge (section 5), and retiring RSA is on the roadmap (section 11).
- Authentication: proving you know your password without revealing it (section 6).
- Key separation: every derived key gets its own domain tag — HKDF-SHA256 under
a distinct
infostring, or HMAC-SHA256 over a distinct label — so compromising one never yields another. Two families deliberately do not come from the master key: the vault key is random and merely wrapped by it, and the recovery keys come from your BIP39 phrase (section 7). - Crypto agility: every scheme carries a version, so we can rotate a primitive without breaking stored data. This is how the post-quantum upgrade in section 11 lands without a rewrite.
4. Data classification
What is and isn’t zero-knowledge:
| Tier | Data | Who can read it |
|---|---|---|
| Zero-knowledge | Identities, vault entries, contacts, SMS/MMS/voicemail content (by default), the anti-phishing marker seed (phrase/colors/avatar) | Only your device |
| Server-encrypted | Phone numbers (routing), E911 addresses (emergency dispatch), SIP credentials, billing metadata, call/SMS cost and carrier metadata | Server can decrypt (required to operate) |
| Blind-indexed | Searchable equality lookups (e.g. by phone) without storing plaintext | Server matches a keyed HMAC, not the value |
| Plaintext | Account ID (a public username), timestamps, primary and foreign keys, is_admin | Anyone with DB access (non-sensitive) |
The carve-outs: phone numbers and E911 addresses are server-readable because the network must route your calls and emergency services must locate you. Voicemail content is zero-knowledge unless you turn on “Listen by phone,” which keeps a server-readable copy so you can hear voicemail by calling in. Your contacts are zero-knowledge unless you turn on “Contact recognition on calls” (off by default), which stores a keyed hash of each contact’s number so we can recognize a known caller on an incoming call — making those numbers recoverable by our servers while it’s on. Turning it off erases those hashes and restores zero knowledge. These are deliberate, opt-in trade-offs for a working phone service, not gaps in zero knowledge.
Server-encrypted fields are bound to their context (for example, an E911 address is cryptographically tied to its owner) so a ciphertext cannot be moved between records. Extending that binding to every server field, plus per-user key derivation, is on our published roadmap.
5. Communications: “server-blind,” not forward-secret
Each inbound SMS, MMS, or voicemail is sealed to your device’s public key (X25519, or the RSA-2048 fallback of section 3 if your device has no X25519 key yet). On the X25519 path we generate a sender keypair, use it once, and destroy it the instant the message is stored; the RSA fallback encrypts straight to your public key, so there is no sender key in the first place. Either way the result is the same: we hold no key that can read your messages: not at rest, not later, not under a warrant served on us. We can be compelled to produce the encrypted bytes; we cannot be compelled to produce a key we do not have.
What this is not: this is not forward secrecy. Your messages are sealed to your device’s long-term key, which is the same key your device uses to re-read your history on a new device. If your private key were compromised, your stored history could be decrypted. We optimize for server-blindness (a server or warrant cannot read your content), which is the achievable and meaningful property for stored, re-readable message history. True forward secrecy conflicts with multi-device history and is not something we claim. Post-quantum hardening of this seal is on our roadmap (section 11).
Carrier-network transit (SS7/SIP) is visible to carriers like all phone service. For end-to-end encryption in transit, use Signal or WhatsApp with your WIGGWIGG number.
6. Authentication
Your password never leaves your device. Today, your device derives the master key (Argon2id) and computes an HMAC-SHA256 proof of it. The server stores only a hash of that proof and compares it on login. The server never sees your password, and an Argon2id-gated master key makes the proof costly to forge.
We are migrating login to an Ed25519 challenge-response scheme in which the server stores only a public key and you prove possession by signing a single-use, 60-second server challenge, so a database leak of the verifier cannot be replayed to log in. This is built and rolling out. We will not claim the stronger “a database leak can’t authenticate” property until the legacy verifier is fully retired.
MFA: WebAuthn/passkeys (phishing-resistant) and TOTP. Anti-phishing: before you type your full password, the site proves itself with a per-account marker (phrase, colors, avatar, optional audio) rendered on your device from a seed we store only in encrypted form. The seed is sealed under a key derived from the first characters of your password — the same characters that gate the reveal (HMAC-SHA256 partial-password check) — so the server never holds a marker it could render, and a database leak alone cannot forge your marker without brute-forcing those characters against the password-stretching KDF. (The protection is bounded by that few-character entropy, not unbreakable: it defeats mass forgery from a stolen database, the scenario an attacker actually exploits after a breach.)
7. Account recovery
Recovery uses a 24-word BIP39 phrase (256 bits of entropy) that you hold and we never see. From it your device derives two separate keys, each under its own domain tag: an X25519 key, which your key material is sealed to, and an Ed25519 signing key, which proves possession of the phrase. We store only public keys and a sealed blob we cannot open.
That blob seals your vault key, not your master key. The distinction matters: the vault key doesn’t change when you change your password, so the recovery envelope never has to be automatically re-sealed. An automatic re-seal is exactly the handle a malicious server would reach for, substituting its own recovery key so it can open the envelope; sealing a stable key means the handle isn’t there. A password change started from recovery is authorized by an Ed25519 signature from your phrase over a single-use server challenge, and your device verifies that the recovered key actually decrypts your data before it re-encrypts anything.
The trusted recovery key is also pinned inside your encrypted preferences, which the server cannot read: if the key it presents doesn’t match the one your device pinned, the operation stops and asks you to confirm your phrase instead of sealing blindly under a server-supplied key.
If you lose both your password and your recovery phrase, your zero-knowledge data is unrecoverable by design: we cannot decrypt it for you. An admin-assisted reset can restore access to your account (phone numbers, billing) but only with your explicit, separate confirmation, and it does not recover the ZK data.
8. Key management and rotation
Server-side keys (the operational field key, the blind-index key, the per-user metadata seed) live in a managed secret store as a versioned ring, validated on startup. Each scheme (KDF, vault-key, asymmetric seal, server key) carries a version column designed for zero-downtime rotation: new writes use the current version, and readers dispatch on the stored version. Crypto-bearing columns are protected by database triggers that refuse to silently null them.
In practice a full server-key rotation runs in a maintenance window today rather than hot: both versions live in the ring, so everything decrypts throughout, and the old version is only retired after a check that refuses to drop it while a single row still depends on it. What’s described here is the mechanism, not a routine operation, and we won’t claim hot rotation until it has been exercised end to end.
9. Application and infrastructure security
- Row-level security: the database itself enforces it on the tables holding
account data (with
FORCE ROW LEVEL SECURITY, a required-context function that raises rather than silently returning rows, and a CI guard), so it refuses to hand one account another’s rows. Extending it to the last legacy tables is in progress. - Transport: TLS everywhere; security headers (CSP/HSTS); CSRF defended via SameSite cookies and strict origin allowlisting.
- Network: per-VPC isolation and per-VPC NAT as deliberate defense-in-depth.
- Encryption at rest: the database, cache, and object storage are encrypted with managed keys (AWS KMS), underneath the application-layer and zero-knowledge encryption above.
- Defense in depth: a managed web application firewall fronts the public edge, with continuous threat detection, control-plane audit logging, VPC flow logs, and encrypted, versioned backups.
- Observability is pseudonymous by default: no raw IP address is stored anywhere. Admin and security audit rows hash it under a server secret, which a database leak alone cannot reverse. The remaining IP hashes are salted per account and per day but carry no secret: bulk reversal is blocked, though someone holding the database could still recover one targeted address. We’re extending the secret to those. Telemetry is designed to carry no user identity, and operational metadata is kept 90 days.
- We don’t keep your user agent. The full string your browser sends is a low-entropy fingerprint, so hashing it obscures it rather than removing it. We reduce it at collection to a coarse label from a fixed 49-value allowlist, like “Chrome / macOS”: no version, no device model, no key. Whatever could single you out is discarded before anything is written. That is data minimization, not anonymization: the label still sits on a row carrying your account id.
- Provider data-minimization: the carrier learns only what routing requires; the card processor (Stripe) receives opaque identifiers and generic line items, and the Bitcoin processor (Blockonomics) sees only a payment address and amount. We never query them about you.
10. Limitations and non-goals
We state these plainly:
- Endpoint compromise. Malware or a malicious extension on your device can read your data after you unlock it. Client-side encryption cannot defend a compromised client.
- No forward secrecy on stored messages (section 5).
- Vault-collection integrity. Each entry is sealed to its own identity, so a server can neither read one nor move it into another field or another account. That does not prove the collection we hand back is complete: a malicious server could omit an entry, serve an older version of one, or reorder them, and your device cannot detect that today. Every stateless zero-knowledge vault shares this residual. The manifest in section 11 is our answer: written and validated, but not yet active, and we won’t claim it until it is.
- Recovery pinning does not yet cover the recovery signing key (section 7): a server that substituted it would cause a denial of service at recovery time, not a read of your data.
- No post-quantum protection yet (section 11): a future quantum adversary could decrypt today’s X25519-sealed data (“harvest now, decrypt later”).
- Phone-service metadata (who called whom, when, for how long) is inherent to the public network and visible to carriers. We minimize and retain it for 90 days, but we cannot make it private.
- Server-readable operational data (phone numbers, E911, billing) is not zero-knowledge (section 4), because it is required to operate.
- Authentication is mid-migration (section 6), so the strongest claim awaits the legacy verifier’s retirement.
11. Roadmap
- Post-quantum (the headline): hybrid X25519 + ML-KEM-768 key wrapping for the message seal and recovery wrap, so an attacker must break both. This directly addresses harvest-now-decrypt-later for long-term stored data.
- Auth: complete the Ed25519 challenge-response rollout and retire the legacy verifier, then evaluate an asymmetric PAKE (OPAQUE).
- Vault-collection integrity: an authenticated manifest under your vault key, the encrypted packing list of your entries plus an anti-rollback counter, so that a server-side deletion, rollback, or reorder becomes detectable by your device. Written and validated across web, mobile, and server; activation waits on a mobile app version floor (section 10).
- Retire RSA-2048 (the communications fallback seal in section 3, and admin support encryption) in favor of the X25519 sealed box.
- Broaden context-binding (AAD) and per-user key derivation across all server-encrypted fields.
- Third-party audit: a planned external cryptographic and application review.
12. Verification and disclosure
- Audit the crypto: github.com/WiggWiggDev/crypto. The KDF, seal, signing, and recovery primitives are exactly what this document describes. Open source proves the design and the client-side primitives; it does not, by itself, prove our servers run them unmodified, so reproducible client builds and published bundle hashes are on the roadmap.
- Report a vulnerability: see our vulnerability-disclosure policy (or the machine-readable security.txt). We offer a good-faith safe-harbor for responsible disclosure and aim to acknowledge within one business day.
This document is versioned and dated. If reality and this document ever disagree, that is a bug in one of them. Tell us.