Le protocole

Voici ce qu’un feeder, un relais ou un client doit parler pour interopérer. La référence est le crate wire du dépôt Tally, le seul code du dépôt qui encode ou décode le protocole, et tous les binaires l’utilisent. Les entiers sont partout en big-endian.

Transport

Chaque saut utilise Noise_IK_25519_ChaChaPoly_BLAKE2s sur TCP. Chaque message Noise est précédé d’une longueur sur deux octets, fait au plus 65 535 octets tag compris, et ne transporte que des enregistrements entiers.

L’identité est une seule clé Ed25519. La clé X25519 qu’authentifie Noise en est dérivée (sk_to_curve25519 de libsodium), et le premier message de handshake de l’initiateur porte sa clé publique Ed25519 de 32 octets, que le répondeur compare à la clé prouvée par le handshake. Une seule clé désigne une antenne partout.

Le préambule

Avant le handshake, l’initiateur envoie 16 octets en clair. Ils servent aussi de prologue Noise, si bien qu’un octet modifié fait échouer le handshake, et ils permettent au handshake lui-même d’évoluer plus tard, et à un relais de détenir une ancienne et une nouvelle clé pendant une rotation.

OctetsChampSignification
0–3Nombre magiqueLes lettres ASCII TALY.
4Version du préambule1.
5Handshake1 : le motif Noise ci-dessus.
6–7RéservéZéro.
8–15Indice de cléÀ laquelle des clés du répondeur la connexion est adressée : les 8 premiers octets du BLAKE2s-256 de sa clé X25519.

Versions

L’initiateur envoie ensuite Hello avec les versions de protocole la plus basse et la plus haute qu’il parle, et son rôle. Le répondeur répond Welcome avec la version que tous deux parleront désormais, ou Goodbye avec une raison et le délai à attendre. Du premier octet à Welcome, il s’écoule au plus 15 secondes, et chaque envoi qui suit a une échéance de 30. La version de protocole 1 est la seule à ce jour.

Un relais accepte, pour toujours, toute version de protocole qu’un feeder a jamais livrée. Les feeders installés ne se mettent pas à jour, et tout le reste du protocole repose sur cette règle.

Enregistrements

Un enregistrement est un octet de type, une longueur de corps sur deux octets, puis le corps. Voici les types que connaît la version 1 du protocole :

TypeEnregistrementCorps
0x01HelloVersion la plus basse, version la plus haute (deux octets chacune), rôle (un octet : 1 feeder, 2 abonné, 3 relais, 4 MLAT, un relais qui publie des positions).
0x02WelcomeLa version que tous deux parleront désormais (deux octets).
0x03BatchLe lot signé d’un récepteur, décrit plus bas. Les relais le transmettent octet pour octet.
0x04ReceiverInfoLa description signée qu’un récepteur donne de lui-même : position et précision de celle-ci, classe d’horloge, logiciel, et les relais qu’il a choisis.
0x05HeartbeatVide. Signe de vie.
0x06RedirectLes secondes à attendre (quatre octets) et des relais suggérés. Il signifie seulement « allez ailleurs » ; le feeder choisit toujours selon ses propres règles.
0x07RelayListLes relais que ce relais connaît, proposés comme suggestions.
0x08RateLimitOctets par seconde et rafale (quatre octets chacun) : le maximum que souhaite le relais. Un feeder peut descendre plus bas, jamais au-dessus du plafond fixé par son propriétaire.
0x09GoodbyeUne raison (un octet) et les secondes à attendre (quatre octets) : le relais ferme la connexion.
0x0aSubscribeLes flux (un octet de drapeaux : 1 brut, 2 dédoublonné, 4 positions), un nombre (deux octets) et autant de cellules H3 (huit octets chacune), 64 au plus. Il remplace le Subscribe précédent de l’abonné.
0x0bRelayBatchUn lot que le relais a signé lui-même : son flux dédoublonné.
0x0cPositionsLes positions calculées par la MLAT d’un relais, signées par ce relais.

Règles d’évolution

Les feeders ne se mettent jamais à jour ; voici donc les règles qui permettent au protocole d’évoluer sans eux :

  • Un type inconnu est ignoré, sauf si son bit de poids fort (0x80) le marque comme critique, ce qui termine proprement la session. Un nouvel enregistrement n’est donc pas critique, sauf si l’ignorer serait une erreur.
  • Un corps peut porter des octets après les champs qu’un lecteur connaît, et ceux-ci sont ignorés. Les nouveaux champs s’ajoutent à la fin.
  • Un lecteur conserve une valeur d’énumération qu’il ne connaît pas comme la valeur Other, jamais comme une erreur.
  • Une forme signée garde le même préfixe dans chaque version de format et se termine par sa signature sur tout ce qui la précède, si bien qu’un relais peut vérifier, router et dédoublonner un format qu’il ne sait pas lire par ailleurs.
  • Le format d’une observation est l’octet de type de BEAST lui-même pour le 1090 MHz. L’UAT 978 MHz prend de nouvelles valeurs sans nouvel enregistrement, et les relais transmettent les formats qu’ils ne connaissent pas.

Le lot signé

Un lot correspond à environ une seconde de réceptions d’un même récepteur. Le format 1 se présente ainsi :

OctetsChampSignification
1Format1.
32CléLa clé publique Ed25519 du récepteur.
8Identifiant de démarrageAléatoire à chaque démarrage du feeder.
8Séquence0, 1, 2 et ainsi de suite au sein d’un même démarrage. Un trou constaté en aval correspond à des données qu’un saut n’a pas livrées.
4Époque du compteurIncrémentée chaque fois que le compteur du récepteur a pu redémarrer, pour que les compteurs d’avant et d’après ne se mélangent jamais.
8Horloge systèmeL’horloge du feeder en millisecondes Unix. À titre indicatif : elle peut être fausse.
4AbandonnéesLes réceptions abandonnées par le plafond propre au feeder depuis le lot précédent.
32PrécédentLe hachage du lot précédent de ce démarrage, des zéros pour le premier, afin qu’un récepteur ne puisse pas signer deux historiques.
4NombreLe nombre d’observations qui suivent.
10 + n chacuneObservationsChacune comprend un format (un octet), le compteur brut 48 bits du récepteur (six), le niveau du signal (un), une longueur (deux) et autant d’octets du message tel que le décodeur l’a émis.
64Signature Ed25519Sur tout ce qui la précède.

Formats d’observation : 1 pour Mode A/C (2 octets), 2 pour Mode-S court (7), 3 pour Mode-S long (14), D pour une liaison descendante UAT 978 MHz, U pour une liaison montante UAT depuis le sol, chacun écrit sous la forme de son caractère ASCII.

La signature couvre le texte ASCII tally batch, un octet nul, et chaque octet du lot avant la signature. Les lots dédoublonnés propres à un relais signent tally relay batch à la place, si bien que l’un ne peut jamais passer pour l’autre.

L’identité d’un lot est le hachage BLAKE2s-256 de tous ses octets, signature comprise. Les relais dédoublonnent sur cette base, et le champ Précédent du lot suivant y fait référence.

Les 49 premiers octets (format, clé, identifiant de démarrage et séquence) gardent leur place dans tout format futur, et la signature vient toujours en dernier.

Personne ne calibre jamais les compteurs avant la MLAT : la MLAT d’un relais a besoin du compteur brut pour calculer une position.