Das Protokoll
Das muss ein Feeder, Relay oder Client sprechen, um mit den anderen zusammenzuarbeiten. Die Referenz ist das wire-Crate im Tally-Repository, der einzige Code dort, der das Protokoll kodiert oder dekodiert, und jedes Binary nutzt es. Ganzzahlen sind durchgehend Big-Endian.
Transport
Jeder Hop ist Noise_IK_25519_ChaChaPoly_BLAKE2s über TCP. Jede Noise-Nachricht wird hinter einer Länge aus zwei Bytes gesendet, höchstens 65.535 Bytes einschließlich Tag, und trägt nur vollständige Records.
Die Identität ist ein einziger Ed25519-Schlüssel. Der X25519-Schlüssel, den Noise authentifiziert, wird daraus abgeleitet (sk_to_curve25519 von libsodium), und die erste Handshake-Nachricht des Initiators trägt seinen öffentlichen Ed25519-Schlüssel (32 Bytes), den der Responder gegen den Schlüssel prüft, den der Handshake bewiesen hat. Ein Schlüssel benennt eine Antenne überall.
Die Präambel
Vor dem Handshake sendet der Initiator 16 Bytes im Klartext. Sie sind zugleich der Noise-Prolog, sodass ein verändertes Byte den Handshake scheitern lässt. Und sie erlauben, den Handshake selbst später zu ändern und ein Relay während eines Schlüsselwechsels einen alten und einen neuen Schlüssel halten zu lassen.
Versionen
Danach sendet der Initiator Hello mit der niedrigsten und der höchsten Wire-Version, die er spricht, und seiner Rolle. Der Responder antwortet mit Welcome und der Version, die beide von da an sprechen, oder mit Goodbye, einem Grund und einer Wartezeit. Vom ersten Byte bis Welcome vergehen höchstens 15 Sekunden, und jedes Senden danach hat eine Frist von 30. Wire-Version 1 ist bisher die einzige.
Ein Relay beantwortet jede Wire-Version, die je ein Feeder ausgeliefert hat, für immer. Installierte Feeder aktualisieren sich nicht, und der Rest des Protokolls beruht auf dieser Regel.
Records
Ein Record besteht aus einem Typ-Byte, einer Inhaltslänge aus zwei Bytes und dem Inhalt. Diese Typen kennt Wire-Version 1:
Regeln für Änderungen
Feeder werden nie aktualisiert, also sind dies die Regeln, nach denen sich das Protokoll ohne sie ändern kann:
- Ein unbekannter Typ wird übersprungen, außer sein höchstes Bit (0x80) markiert ihn als kritisch, was die Sitzung sauber beendet. Neue Records sind daher nicht kritisch, es sei denn, sie zu ignorieren wäre falsch.
- Ein Inhalt darf nach den Feldern, die ein Leser kennt, weitere Bytes tragen, und diese werden ignoriert. Felder kommen hinzu, indem sie angehängt werden.
- Ein Enum-Wert, den ein Leser nicht kennt, behält er als den Wert Other, nie als Fehler.
- Eine signierte Form behält in jeder Formatversion dasselbe Präfix und endet mit ihrer Signatur über alles davor, sodass ein Relay ein Format prüfen, routen und deduplizieren kann, das es sonst nicht liest.
- Das Format einer Beobachtung ist für 1090 MHz das Typ-Byte von BEAST selbst. 978-MHz-UAT bekommt neue Werte und braucht keinen neuen Record, und Relays leiten Formate weiter, die sie nicht kennen.
Der signierte Batch
Ein Batch umfasst etwa eine Sekunde an Empfangsdaten eines Empfängers. Format 1 ist so aufgebaut:
Beobachtungsformate: 1 ist Mode A/C (2 Bytes), 2 Mode-S kurz (7), 3 Mode-S lang (14), D ein 978-MHz-UAT-Downlink, U ein UAT-Uplink vom Boden, jeweils als ASCII-Zeichen geschrieben.
Die Signatur umfasst den ASCII-Text tally batch, ein Null-Byte und jedes Byte des Batches vor der Signatur. Die eigenen deduplizierten Batches eines Relays signieren stattdessen tally relay batch, sodass der eine nie als der andere durchgehen kann.
Die Identität eines Batches ist der BLAKE2s-256-Hash aller seiner Bytes, Signatur eingeschlossen. Relays deduplizieren danach, und das Feld Vorgänger des nächsten Batches nennt ihn.
Die ersten 49 Bytes (Format, Schlüssel, Boot-ID und Sequenz) behalten ihren Platz in jedem künftigen Format, und die Signatur kommt immer zuletzt.
Zähler werden vor dem MLAT nie kalibriert, von niemandem: Das MLAT eines Relays braucht den rohen Zähler, um zu rechnen.