Features
A closer look at the handshake, the verification checks, and the tools built around them.
The Handshake — Step by Step
The IRLid handshake is a three-step protocol that produces a cryptographic receipt in about ten seconds. Each step diagram below shows what happens on each phone and what data is exchanged.
Show Your HELLO QR
Person A (the Initiator) opens IRLid on their phone. The app automatically generates a signed HELLO QR code and displays it full-screen. This QR encodes a compact JSON payload containing the device's ECDSA P-256 public key, the current GPS coordinates (rounded to ~1.1m precision), a Unix timestamp, and a random nonce.
The entire payload is signed with the device's private key, which means the QR itself is a self-contained cryptographic assertion: "I am the holder of this key, and I was at this location at this time."
Scan & Accept
Person B (the Collaborator) scans A's QR code using their phone's standard camera — no app switch needed. The QR links to the IRLid Accept page, which decodes A's HELLO, verifies the signature and timestamp, then creates a signed response.
The response is cryptographically bound to A's specific HELLO via a SHA-256 hash. This binding is critical: it means B's response cannot be replayed against a different HELLO from a different person or time. B's phone displays the Accept QR and waits.
Verify & Receipt
Person A opens the Scan page and points their camera at B's Accept QR. The app decodes B's response and runs a full verification suite: it checks B's signature, confirms the HELLO binding hash matches, validates that both timestamps are within 90 seconds of each other, and measures the GPS distance between both devices (must be within 12 metres).
If all checks pass, the two signed payloads are combined into a single receipt object. This receipt is uploaded to the IRLid server and becomes available to both parties. Anyone with the receipt hash can independently re-run every cryptographic check on the Check page.
Verification Checks
Each receipt is scored against a series of independent checks. The receipt page and Check page display a percentage bar that reflects how many checks passed. Here is the full breakdown:
-
Initiator structure — The initiator's response contains all required fields: payload, hash, signature, and public key.
-
Initiator hash — The SHA-256 hash of the initiator's payload matches the hash field. This confirms the payload hasn't been tampered with.
-
Initiator signature — The ECDSA signature over the hash verifies against the initiator's public key.
-
Collaborator structure — Same structural check for the collaborator's response.
-
Collaborator hash — The collaborator's payload hash is independently recomputed and matched.
-
Collaborator signature — The collaborator's ECDSA signature is verified against their public key.
-
HELLO binding — Both responses contain a hash that matches the original HELLO, proving they were created for this specific handshake.
-
Time delta — The difference between both timestamps is within the 90-second tolerance window.
-
Distance — The GPS coordinates from both devices are within 12 metres of each other, confirming physical co-presence.
Platform Features
No App Required
IRLid runs entirely in the browser. No download, no install, no app store. Works on any phone with a camera and a modern browser.
Device Key Pairs
Each browser generates a unique ECDSA P-256 key pair using the Web Crypto API. The private key never leaves the device — it's stored in localStorage and used only for signing.
Google Account Linking
Optionally link a Google account to attach your name and profile picture to receipts. Multiple devices can be linked to one account via a 6-digit code.
Receipt History
All your receipts are stored server-side and accessible from your account page. Receipts are visible to both parties — if your key was involved, the receipt appears in your list.
Third-Party Verification
Anyone can verify a receipt on the Check page by pasting a receipt hash or URL. All cryptographic checks run in the browser — no login required, no trust in the server needed.
Compressed QR Codes
Payloads are deflate-compressed before encoding into QR codes. This keeps QR codes scannable even with the full cryptographic data (public keys, signatures, GPS, timestamps).
Passkey Support
WebAuthn passkey authentication is available for device-local login, providing biometric-gated access without sending credentials to a server.
Open Source
The full codebase — frontend, Cloudflare Worker backend, D1 database schema — is on GitHub. Audit the crypto, run your own instance, or contribute.
Security Model
IRLid's security comes from layering independent constraints. A valid receipt requires correct ECDSA signatures from two distinct key pairs, hash bindings that chain the responses to a specific HELLO, timestamps within a tight window, and GPS proximity. An attacker would need to simultaneously control two devices at the same time and location while also possessing the private keys — which is equivalent to actually being there.
The server never sees private keys. It stores only the combined receipt JSON (which contains only public keys and signed data) and optional profile information. The server performs its own verification at upload time, but this is a convenience check — the receipt is self-verifying and can be validated by anyone with the raw JSON.