# 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 (2–n)** – 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 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) │ │ ├─ B–C direkt verbunden! │ ├─ B–C 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