randomp2p/README.md

156 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# randomp2p
**Vertrauensloser Multiplayer-Münzwurf P2P im Browser, keine Server, kein Trust.**
Zwei bis N Spieler verbinden sich via WebRTC (simple-peer) und führen ein kryptografisches Commit-Reveal-Protokoll aus, um einen garantiert fairen Münzwurf zu erhalten. Solange **ein** Teilnehmer ehrlich ist, ist das Ergebnis zufällig und manipulationssicher.
## Features
- **P2P** Kein Server, kein Account, keine zentrale Instanz
- **Trustless** Commit-Reveal-Protokoll mit SHA-256-Bindung, jeder verifiziert
- **QR-Bootstrapping** SDP-Offers/Answers werden als QR-Codes ausgetauscht
- **Multiplayer (2n)** Beliebig viele Teilnehmer in einer Runde
- **Full Mesh** Alle Peers verbinden sich direkt per WebRTC (Host relayt nur initial SDP)
- **Selective Abort** Timeout erkennt Verweigerer, alle Teilnehmer sehen denselben Schuldigen
- **Coin-Animation** 3D-Münzwurf via CSS
- **100% Vanilla JS** Keine Build-Tools, kein npm, keine Abhängigkeiten außer CDN-Libs
## Quick Start
```bash
git clone <repo-url>
cd randomp2p
python3 -m http.server 8080
```
Dann auf zwei (oder mehr) Geräten `http://localhost:8080` öffnen.
> WebRTC + Kamera (`getUserMedia`) + Web Crypto API brauchen einen **sicheren Kontext**. Lokal via localhost funktioniert das. Für andere Geräte im selben Netzwerk die lokale IP verwenden.
## Spielanleitung
### Host
1. **"Raum erstellen"** QR-Code mit SDP Offer wird angezeigt
2. **"Antwort-QR scannen"** Kamera startet, scannt die Antwort-QRs der Beitreter
3. Jeder neue Spieler erscheint in der Liste
4. Host broadcastet `roster` mit allen Peer-IDs → Peers bauen direktes Mesh untereinander auf
5. Sobald alle Peers `mesh_ready` gemeldet haben → **"Münzwurf starten"** wird aktiv
6. **"Münzwurf starten"** Übergang in den Spiel-Screen
7. **"Münzwurf starten"** Protokoll beginnt (Commit → Reveal → Ergebnis)
### Beitreter
1. **"Raum beitreten"** Kamera startet
2. QR des Hosts scannen
3. **Antwort-QR zeigen** Host scannt diesen QR
4. Verbindung steht, empfange `roster` mit anderen Peer-IDs
5. Baue direkte WebRTC-Verbindung zu jedem anderen Peer auf (kleinere PeerId initiiert → kein Glare)
6. Sobald alle direkten Verbindungen stehen → automatisch `mesh_ready` an Host
7. Host startet Protokoll → alle laufen automatisch durch (Commit → Reveal → Ergebnis)
### Protokoll-Phasen
| Phase | Beschreibung |
|-------|-------------|
| **Commit** | Jeder Spieler generiert 32 Zufallsbytes und sendet den SHA-256-Hash an alle |
| **Warten** | Sammle Commits aller Teilnehmer (Timeout 12s) |
| **Reveal** | Jeder sendet die rohen Zufallsbytes an alle |
| **Warten** | Sammle Reveals aller Teilnehmer (Timeout 12s) |
| **Verify** | Jeder prüft: SHA-256(received) == stored_commit |
| **Result** | XOR aller Secrets → Parity (0=Kopf, 1=Zahl) |
Bei Timeout in einer Wartephase: **Selective Abort** `ABORTED`-Zustand, fehlende Peer-IDs werden angezeigt.
Alle Teilnehmer sehen dieselben fehlenden Peers (Mesh → jeder sieht, wer nicht sendet).
## Architektur
```
randomp2p/
├── index.html 5 Screens + CDN-Libs
├── style.css Dark-Theme, Coin-Animation
├── crypto.js SHA-256, Zufallsbytes, XOR-Combine
├── p2p.js MeshNet: simple-peer, QR-Signaling, Datenkanal
├── protocol.js Commit-Reveal State Machine
└── app.js UI-Routing, Kamera/QR-Scan, Verkabelung
```
### Abhängigkeiten (CDN)
| Library | Zweck |
|---------|-------|
| [simple-peer](https://github.com/feross/simple-peer) | WebRTC-Datenkanäle |
| [qrcodejs](https://github.com/davidshimjs/qrcodejs) | QR-Code-Generierung |
| [jsQR](https://github.com/cozmo/jsQR) | QR-Code-Scanning per Kamera |
## Netzwerk-Topologie
**Phase 1 Stern (QR-Bootstrapping):**
Host tauscht via QR-Codes SDP Offers/Answers mit jedem Peer aus → jeder Peer ist direkt mit dem Host verbunden.
**Phase 2 Mesh (relayed Signaling):**
Sobald ein Peer beitritt, broadcastet der Host ein `roster` mit allen Peer-IDs an das gesamte Netzwerk.
Jeder Peer baut zu jedem anderen Peer eine **direkte WebRTC-Verbindung** auf:
- **Initiator** ist immer der Peer mit der **kleineren PeerId** (verhindert Glare / Race-Conditions)
- SDP Offers/Answers werden über den **Host als Relay** ausgetauscht (`signal_relay`/`signal_relayed` via DataChannel)
- Nach erfolgreichem Verbindungsaufbau sendet jeder Peer `mesh_ready` an den Host
**Ergebnis:** Volles Mesh jeder Peer ist mit jedem direkt verbunden.
Broadcasts erreichen alle Teilnehmer in einem Hop. `expectedPeers` (für Timeout/Abort) ist auf allen identisch.
```
Host A ──QR── Peer B Host A ──star── Peer B
Host A ──QR── Peer C → Host A ──star── Peer C
Peer B ──mesh── Peer C (direkt, kein Relay)
```
### Signal-Relay-Detail
```
B (Initiator, peerId kleiner) Host A C (Responder)
│ │ │
├─ signal_relay(to:C, offer) ──────→│ │
│ ├─ signal_relayed(offer) ──→│
│ │ ├─ SimplePeer(non-init)
│ │ ├─ peer.signal(offer)
│ │ ├─ answer signal
│ │←─ signal_relay(to:B, answer) ─┤
│←── signal_relayed(answer) ────────┤ │
├─ peer.signal(answer) │ │
├─ BC direkt verbunden! │ ├─ BC direkt verbunden!
│ │ │
├─ mesh_ready ────────────────────→│←────────────────── mesh_ready ─┤
│ │ readyPeers={B,C} → Button enabled
```
## Warum ist das fair?
Das Commit-Reveal-Protokoll garantiert:
1. **Keine späte Manipulation:** Der SHA-256-Commit bindet jeden Spieler vor dem Reveal an sein Secret (Preimage-Resistenz)
2. **Keine Absprache nötig:** Solange **ein** Teilnehmer ehrlich Zufallsbytes beisteuert, ist das XOR-Ergebnis zufällig
3. **Volle Transparenz:** Jeder Teilnehmer rechnet lokal alle Prüfungen und das Endergebnis
Mathematisch: `result = S_1 ⊕ S_2 ⊕ ... ⊕ S_n`. Wenn `S_k` echt zufällig und vor `S_1..S_{k-1}, S_{k+1}..S_n` festgelegt wurde, ist `result` zufällig unabhängig von allen anderen Secrets.
## IPFS-Deployment
```bash
ipfs add -r .
# → CID notieren, über IPFS-Gateway aufrufbar
# → Gateway-URL als QR-Code in die App einbauen
```
## Ausblick / TODOs
- [x] Volles Mesh: Peers verbinden sich direkt via relayed signaling
- [x] Selective Abort: Timeout bei Verweigerern
- [ ] Reconnect bei Verbindungsabbruch
- [ ] Raum-Code als Alternative zum QR-Scan
- [ ] TURN-Server-Konfiguration für NAT-Traversal
- [ ] PWA-Manifest + ServiceWorker für IPFS-Distribution
## Lizenz
MIT