| Version | |
|---|---|
| Proof-of-Concept Implementation | 0.1 |
| Specification | 0.3 (changelog) |
Warning
This repository contains proof-of-concept code and is not intended for production use. The protocol details are not yet finalized.
January 2025: A formal analysis was performed by Luca Maier in https://github.com/lumaier/securedrop-formalanalysis and published as "A Formal Analysis of the SecureDrop Protocol", supervised by David Basin, Felix Linker, and Shannon Veitch in the Information Security Group at ETH Zürich.
May 2024: Proof-of-concept code was announced publicly.
December 2023: A preliminary cryptographic audit was performed by Michele Orrù. See #36.
Jan 2023: Proof-of-concept implementation work with Shielder began.
To better understand the context of this research and the previous steps that led to it, read the following blog posts:
- Part 1: Future directions for SecureDrop
- Part 2: Anatomy of a whistleblowing system
- Part 3: How to research your own cryptography and survive
- Part 4: Introducing SecureDrop Protocol
Install the Rust toolchain. To view browsable documentation, install doxygen and dot (Graphviz). Use make help from the project root to see available make targets, e.g. to install lint tools, run formatting checks, or build crates.
Lint tools are installed in the lint-tools directory to avoid interfering with the user's system dependencies; cargo will suggest adding the directory to your $PATH, but that's not required.
The benchmarks were performed on an Apple MacBook Air M4 to assess the protocol's performance on typical consumer hardware. All source code and the Makefile are located in the securedrop-protocol subfolder.
Dependencies (install via Homebrew unless noted):
rustc1.92.0 (via rustup)- Node ≥ 22
- GCC (required for Rust compilation)
- Firefox
- Chrome
Run a quick sanity‑check with a few iterations:
make quick-benchRun the full benchmark suite:
make benchTwo benchmark types are implemented: iterative benchmarks and sweep benchmarks. The iterative benchmark measures three core protocol operations:
- encrypt – encrypt a payload
- decrypt – decrypt using a single key bundle
- solve – solve a single challenge
These operations provide the baseline for the iterative and configurable protocol functions. For example, a Journalist decrypt repeatedly calls the decrypt primitive for all currently active Journalist key bundles, while a retrieve runs the solve function on every challenge returned by the server.
Sweep benchmarks evaluate client performance as configurable system parameters grows. One sweep measures the journalist‑decrypt function while increasing the number of active key bundles; the other measures the retrieve operation as the maximum number of system messages grows. As expected, runtimes scale roughly linearly, but WebAssembly optimisations can become significant when the number of iterations grows and the startup cost is amortised.
Results are saved in the out directory in both JSON and CSV formats. By default each benchmark iteration uses a fresh browser profile. The underlying Node script also supports a mode that runs without restarting the browser, looping over the WebAssembly functions. This mode yields extremely fast numbers in some cases because of optimisations and predictions that would not occur in real‑world usage, and therefore can produce misleading results.
A TikZ chart of the iterative benchmark can be generated with the chart.js script. After running the benchmark at least once, note the folder shown in the output, for example out/20260112-222635/. Then execute:
node chart.js out/20260112-222635/all_samples.csvThe script prints the TikZ code for the chart to the console, which you can copy into a LaTeX document.
wasm-bindgen exposes Rust objects and functions in Javascript in the benchmarking code. If troubleshooting, ensure you are using the same version of the wasm-bindgen cli as is specified in Cargo.toml (wasm-bindgen -V).
wasm-bindgen requires wrapper classes for Rust objects to marshall in and out of Javascript. If any structs or function signatures that are being used in www/index.html (rendering benchmarks) are changed, the corresponding wrapper structs, annotated with #[wasm_bindgen], will need to change accordingly.
If the wasm-compiled Rust code panics, the browser may display a fairly generic/unhelpful message with limited information (for example, {"error":"unreachable executed"}). Add the console_error_panic_hook crate and use the console_error_panic_hook::set_once(); method in a common codepath annotated by #[wasm-bindgen] in order to log further information to the browser console. You will also need to temporarily adjust Cargo.toml:
[profile.release]
panic = "unwind"
[profile.dev]
panic = "unwind"
You may also need to follow the console_error_panic_hook docs to increase the stacktrace lines printed by your browser.