- What: Introduces IRLid Protocol for proof-of-personhood without biometrics
- Impact: Technical community and developers
Proof-of-Personhood Without Biometrics: The IRLid Protocol Published April 2026 ยท irlid.co.uk With Reddit rolling out mandatory human verification and World ID expanding its iris-scanning Orb into Discord, Shopify, and beyond, proof-of-personhood is suddenly a mainstream problem. Most proposed solutions fall into two camps: behavioural analysis (invisible, low-trust) or biometrics (high-trust, high-privacy cost). This writeup describes a third approach โ anchoring proof of personhood to a physical real-world interaction between two devices, with no biometric capture and no backend server. This is a technical writeup intended for developers and security researchers. It describes the protocol honestly, including its known limitations and attack surface. Critique is welcome. 1. The Problem The core question is: how do you establish that an account is controlled by a unique human, without learning anything else about that human? Behavioural analysis (reCAPTCHA, Cloudflare Turnstile, Arkose) answers a weaker question: "does this session look like a human?" It fails against sophisticated bots, leaks behavioural telemetry, and produces a probability score rather than a guarantee. Biometric approaches (World ID's iris scan, Face ID) answer a stronger question but require a trusted hardware device, a central database of biometric proofs, and an implicit trust relationship with whoever operates that database. The specific threat model IRLid addresses: can two parties produce a jointly-signed, time-stamped, location-bound proof that they were physically co-present, using only their existing devices and a QR code exchange? No proprietary hardware. No biometric capture. No always-online server. 2. Protocol Overview IRLid is a two-scan handshake between two devices. Each device generates a local ECDSA P-256 keypair (via the Web Crypto API) on first use. The private key never leaves the device. The handshake proceeds as follows: Step 1 โ HELLO (Offer) Person A opens IRLid. The application acquires A's GPS position and generates a signed HELLO object: { "v": 2, "type": "hello", "pub": { /* A's ECDSA P-256 public key as JWK */ }, "nonce": 3847261049, "ts": 1743750000, "offer": { "payload": { "v": 1, "type": "offerPayload", "lat": 51.509865, "lon": -0.118092, "acc": 8.3, "ts": 1743750000, "nonce": 3847261049 }, "hash": "base64url(SHA-256(canonical(offerPayload)))", "sig": "base64url(ECDSA_P256_sign(hash, A_privKey))" } } This object is base64url-encoded and embedded in a URL, which is rendered as a QR code for B to scan. Step 2 โ ACCEPT (Response) B scans A's QR. B's device first verifies the HELLO: it checks the offer hash, verifies A's signature, and confirms the timestamp is within the 90-second tolerance window. If the HELLO is valid, B's device acquires its own GPS position and constructs a signed response that binds to both the HELLO hash and the signed offer hash: { "v": 2, "type": "response", "payload": { "v": 1, "type": "payload", "helloHash": "base64url(SHA-256(HELLO_bytes))", "offerHash": "base64url(SHA-256(offerPayload_bytes))", "lat": 51.509871, "lon": -0.118085, "acc": 6.1, "ts": 1743750042, "nonce": 2918476305 }, "hash": "base64url(SHA-256(payload_bytes))", "sig": "base64url(ECDSA_P256_sign(hash, B_privKey))", "pub": { /* B's ECDSA P-256 public key as JWK */ } } B's response is shown as a QR for A to scan. Step 3 โ Combined Receipt A scans B's response. A's device verifies B's signature and payload, then checks mutual tolerances: Time delta: |ts_A โ ts_B| โค 90 seconds Distance: haversine(GPS_A, GPS_B) โค 12 metres HELLO binding: B's helloHash and offerHash match the original HELLO Signature validity: both ECDSA signatures verify against their respective public keys If all checks pass, a combined receipt is produced: { "v": 2, "type": "combined", "tol": { "dist_m": 12, "ts_s": 90 }, "hello": { /* original signed HELLO from A */ }, "a": { /* A's signed response */ }, "b": { /* B's signed response */ } } This combined receipt is itself base64url-encoded and embedded in a URL, rendered as a QR. Anyone with a QR scanner can open the receipt and verify all signatures client-side โ no server call required. 3. Cryptographic Primitives Primitive Choice Rationale Key algorithm ECDSA P-256 Native WebCrypto support across all modern browsers; hardware-backed on devices with a secure enclave Hash SHA-256 Standard; used for both payload hashing and signature input Key storage localStorage (JWK) Current approach โ see limitations below Encoding base64url (RFC 4648 ยง5) URL-safe, no padding issues in QR/hash fragments Distance Haversine formula Sufficient precision at โค12m scale 4. Security Properties What the protocol provides Co-presence guarantee (conditional): Both parties must have been at the same GPS location (ยฑ12m) within the same 90-second window. A bot cannot satisfy this without physical hardware at the location. Replay resistance: Each HELLO contains a fresh nonce and a timestamp. Responses bind to both the HELLO ha...