# Threshold MPC file demo

An experimental browser demonstration of **2-of-3 AES-128-GCM encryption and decryption inside secure multiparty computation**. It uses three party workers, direct MessagePorts and the published EMP WebAssembly engine. There is no Shamir reconstruction followed by WebCrypto AES.

## Run locally

No npm install, build, CDN, account or internet connection is needed to run the included demo. All runtime dependencies are vendored; the WASM binary is embedded in `vendor/emp-runtime-worker.js`.

- **Windows:** install Python 3 if necessary, extract this ZIP, then double-click `Start.bat`. It serves the folder and opens your browser.
- **Linux/macOS:** from the extracted folder, run `python3 scripts/serve.py --open` (or `./Start.sh` and visit the address printed).
- Open **http://127.0.0.1:8765** in Chrome/Chromium. Keep the terminal running. Ctrl+C stops the server.
- If port 8765 is occupied, use `python3 scripts/serve.py --port 8767 --open` (Windows: `py -3 ...`).

The Python server only serves local static files on the loopback address. It does not perform encryption or receive file uploads. Another static localhost server works too. Do not double-click index.html: module workers and fetch require HTTP/HTTPS, not file://.

## Try it

1. Generate the three shares.
2. Click **Use tiny sample**, then **Encrypt file**. Encryption uses A+B.
3. Download the encrypted container if desired. The same container is also retained for immediate decryption.
4. Select A alone, B alone or C alone and click Decrypt: each is rejected.
5. Select AB, AC or BC: each runs an actual two-party MPC computation and provides the original file for download.
6. The developer section has an automated six-combination button. It runs genuine MPC for pairs; its single-party checks are UI/API rejection checks. The supplied automated browser suite also tests missing peers below that validation.

**Keep this page open.** Shares are intentionally ephemeral. Reloading, closing the tab or generating new shares destroys access to previous containers in this demo. No persistence or share import/export is implemented. Party debug buttons print private components only in the respective worker's console; keep them off for normal use.

## Performance and limits

Start with a few bytes. A measured three-byte encryption took about 20 seconds in headless Chromium on the build environment, with 204,435 gates and about 19 MiB sent by one party. Hardware and browser performance vary considerably.

Files are processed in 64-byte chunks; each chunk uses a fresh MPC session and AES-GCM nonce. Larger files are accepted but are impractically slow. Circuit size is bounded per chunk, while the container and recovered file still consume memory proportional to file size. Each MPC session times out after 180 seconds. No production throughput or browser-wide compatibility claim is made.

## Security scope

This is genuine garbled-circuit execution, but **this integration and the WASM port are unaudited**. The upstream README explicitly identifies uncertain porting changes. We conservatively assume honest protocol execution, an honest coordinator, at most one passively observed party, secure randomness, and an uncompromised browser. Do not use this for valuable secrets.

The key exists mathematically and as distributed/encoded circuit wires. No participant in normal execution receives its clear bytes. A circuit variable named `key` contains wire IDs, not key bits. The coordinator receives only public state, agreed output and statistics.

This does not prevent two deliberately colluding holders from combining their shares outside the protocol. Three workers on one machine do not protect against its owner or DevTools. See `docs/SECURITY.md` for exact boundaries.

## Architecture and audit entry points

| Path | Purpose |
|---|---|
| index.html, app.js, style.css | Local UI and download links |
| coordinator/parties.js | Worker lifecycle, public requests and pair selection |
| coordinator/files.js | Chunk container, metadata binding, nonce allocation |
| party/worker.js | Private replicated share state, circuit inputs |
| crypto/circuit.js | Public circuit construction: AES-GCM and output gating |
| crypto/engine.js | Party-local adapter to upstream EMP worker |
| vendor/ | AES circuit and published EMP runtime; no network fetches |
| tests/ | Known-answer and real browser MPC tests |
| docs/ | Protocol, assumptions, upstream notes and provenance |

Direct MessagePorts carry setup components and online MPC messages. They are transferred to the party workers and then inaccessible to the coordinator. For remote participants, replace these transports with authenticated confidential peer channels. This version does not implement remote-device discovery or authentication.

## Tests

For development/testing only, install Node.js and Python 3, then run:

```sh
npm ci
npx playwright install chromium
npm test
```

On Windows, change the `python3` command in playwright.config.js to `py -3` if Python is available only through the Windows launcher.

`npm run test:circuit` checks the generated GCM circuit against Node/OpenSSL for lengths 0, 1, 15, 16, 17 and 64, including invalid tags. These tests use public fixture keys and a clear circuit evaluator confined to the test file. The application never imports that evaluator.

`npm run test:browser` launches local headless Chromium, exercises all pairs on the same container, tests solitary workers with no peer, authenticates a multi-chunk binary file and rejects a modified tag. See `tests/latest-results.txt` for the recorded execution result.

Functional tests are not a proof of secrecy or an audit. The complete reusable key remaining hidden also relies on the selected MPC implementation and the stated assumptions.
