S.04Systems2026active

PhotonQR

Moving files across an air gap, one screenful at a time

Every file transfer tool assumes a shared network. PhotonQR assumes the opposite: two devices that can see each other and nothing else. What comes back is a real protocol problem — framing, error correction, flow control — solved through a camera.

Cipher
AES-256-GCM
header bound as AAD
Dropped frames
Carousel
no back-channel needed
Throughput ceiling
~4 KB/s
QR v15 at 12 fps
Network permission
None
no code path exists

The sender renders a file as a sequence of QR frames on screen; the receiver films them through its camera and reassembles the bytes. There is no pairing step, no shared network, and no radio involved — which means the transfer works in places where every other method is either unavailable or disallowed.

Honest about being slow

At QR version 15 and twelve frames per second the ceiling is roughly four kilobytes per second before losses. A 50 KB document takes about twenty seconds; a 3 MB photo takes about twenty minutes; a 200 MB video is not practical. The Send screen states the estimate before you begin, because a user who picks a large video without being warned will reasonably conclude the app is broken when it is still going an hour later.

The protocol

Every packet is encrypted with AES-256-GCM, with the frame header bound in as associated data so a tampered header fails authentication rather than silently mis-routing a chunk. CRC-32 and the authentication tag reject corrupted frames, and because there is no back-channel to request a retransmit, the sender loops: a dropped frame simply comes round again. A Reed–Solomon erasure code over GF(256) is implemented and tested in the repository, but the current send path does not use it yet. The completed file is verified against the sender's SHA-256 digest before it is written.

  • Any binary file — the protocol carries bytes, with no type restrictions.
  • Automatic compression, skipped when it would not help: JPEG, MP4, ZIP and APK are detected and stored verbatim rather than expanded.
  • Adaptive optimisation that diagnoses why throughput is low before changing anything.
  • Resume across app restarts, so a long transfer survives being interrupted.
  • Developer mode with a live protocol monitor.

No network permission at all

The application declares no network permission, and there is no code path that could use one. For a tool whose entire purpose is moving data without a network, that is the difference between a privacy claim and a structural guarantee: it cannot phone home, and you can verify that from the manifest rather than taking my word for it.

Built on Flutter 3.35.7 for Android API 24+ and iOS 12+, in a feature-first clean architecture with no circular dependencies, and wired to GitHub Actions for CI and releases.

L.02 Real protocol, real frames

Send me across the air gap

This page is a PhotonQR sender. Type a message and transmit it, then point the app's Receive screen at these frames. Each one is AES-256-GCM encrypted in your browser and looped until you stop.

Waiting for a message

Starting it makes the code flicker at 6 frames a second, or 1 with reduced motion on.

Checked by decoding these frames with the app's own Dart code: header, key derivation, decryption, reassembly and digest. Not yet tried with a real camera and screen. The key travels in the first frame, as in the app's default mode, so anyone filming the whole loop can read it. Get the app or read how it works.

Longer read / 6 minSpeaking Photon from a browser

Search only: every answer quotes this site and links its source. Nothing is generated.