RFC XXXX, Format de données pour le protocole JNTP, Version 1.0


             Format de données pour le protocole JNTP
                  (JSON News Transfer Protocol)

Résumé

   Ce document spécifie la syntaxe des articles et autres données
   échangés par le protocole JNTP (JSON News Transfer Protocol)
   dont la finalité est de proposer une alternative à l’ensemble
   de protocoles Netnews, non plus basée sur l’Internet Message
   Format (RFC 5322) mais sur la JavaScript Object Notation (JSON)
   (RFC 7159).

Statut du présent mémoire

   [sera rempli par le RFC Editor]

1. Introduction

   Les protocoles Netnews (RFC 5536 et 5537), qui permettent d’échanger
   des messages selon un algorithme d’inondation, ont depuis longtemps
   prouvé leur utilité et leur efficacité. Cependant le format utilisé,
   qui est un sous-ensemble du format des messages de courriel, bien
   qu’il permette de transmettre tous types de données, n’est pas le
   plus efficace s’agissant de données binaires. En particulier il ne
   permet pas de transmettre d’abord un résumé du message (ne contenant
   que des données textuelles) puis de délivrer les différentes données
   binaires sur demande.

   Le protocole JNTP (JSON News Transfer Protocol) tente de répondre à
   ce besoin. Basé sur la JavaScript Object Notation (JSON) [RFC7159]
   au lieu d’être basé sur l’Internet Message Format [RFC5322] et sur
   Multipurpose Internet Mail Extensions (MIME) [RFC2045], il est
   directement utilisable au travers d’un simple navigateur web au
   lieu de nécessiter un logiciel de nouvelles spécifique, même si
   bien sûr des logiciels spécifique à JNTP peuvent être développés.

   Ce document définit le format de données utilisé par le protocole
   JNTP. Le document (titre à donner) [RFCYYYY] définit différents
   types de données à commencer par le type "Article". Le document
   (titre à donner) [RFCZZZZ] définit le protocole JNTP en lui-même.

1.1. Conventions Used in This Document

   Les mots clés "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", et "OPTIONAL" de ce
   document doivent être interprétés comme il est décrit dans [RFC2119].

   Les règles grammaticales de ce document doivent être interprétées
   comme il est décrit dans [RFC5234]. Par ailleurs les règles définies
   dans [RFC7159] qui ne sont pas redéfinies dans ce document sont
   implicitement incluses dans ce document.

   Dans les exemples qui parsèment ce document, une ligne terminée
   par le caractère \ doit être considérée comme se continuant sur
   la ligne suivante. Par exemple, le texte :
      "content" : "This i\
      s an example of wra\
      pped line"
   doit être lu comme :
      "content" : "This is an example of wrapped line"

2. Grammaire JNTP

   Toutes les données échangées et manipulées par le protocole JNTP
   sont représentées en utilisant la syntaxe Javascript Object
   Notation (JSON) [RFC7159].

   Plus précisément, un sous-ensemble de JSON est utilisé, car des
   restrictions sont apportées aux types ‘object’ et ‘number’.

2.1. Restrictions sur le type ‘object’

   Dans la section 4 de JSON [RFC7159], la structure ‘object’ est
   définie comme un ensemble de membres qui sont des paires nom/valeur,
   le nom étant de type ‘string’ sans aucune restriction.

   Dans JNTP, le ‘nom’ de chaque paire nom/valeur, que l’on désignera
   par le terme ‘clé’ dans le reste de ce document, ne peut contenir
   que des lettres, des chiffres, ou des caractères "-" ou "_",
   éventuellement précédés par un "#".

      object = begin-object [ member *( value-separator member ) ]
      end-object

      member = key name-separator value

      key = quotation-mark [ directive ] key-name quotation-mark

      directive = "#"

      key-name = 1*key-char

      key-char = ALPHA / DIGIT / "-" / "_"

   La partie optionnelle ‘directive’ est expliquée dans la section
   suivante de ce document.

   La partie ‘key-name’ DOIT contenir au moins 1 caractère et DEVRAIT
   contenir au maximum 20 caractères. Les clés "" et "#" sont donc
   interdites en JNTP alors qu’elles sont autorisées en JSON.

   Par ailleurs, alors que JSON demandait seulement par un SHOULD que
   les noms soient uniques au sein d’un même objet, dans JNTP cette
   contrainte est un MUST, et elle concerne la partie ‘key-name’ de
   la clé, indépendamment de la présence ou de l’absence d’une
   directive. Ainsi, une seule des deux clés "content" ou "#content"
   peut se trouver dans un objet donné.

2.2. Restrictions sur le type ‘number’

   Dans la section 6 de JSON [RFC7159], les nombres sont définis
   par leur représentation décimale à l’exclusion de toute autre
   représentation, sans imposer de limites de grandeur ou de
   précision. Néanmoins cette spécification autorise les
   implémentations à fixer de telles limites, et rappelle que
   le format IEEE 754-2008 binary64 (double precision) [IEEE754]
   est généralement disponible et largement utilisé.

   Afin de limiter au maximum les problèmes d’interopérabilité,
   JNTP impose aux nombres les limites suivantes, compatibles
   avec le format IEEE 754-2008 binary64.

   a) Le nombre de chiffres significatifs (du premier au dernier
      chiffres non nuls, quelles que soient la position d’un
      éventuel point décimal et la valeur d’un éventuel exposant)
      ne peut pas dépasser 15 chiffres.

   b) En dehors des valeurs nulles (-0 et 0), les nombres doivent
      être compris entre -9.99999999999999e+307 et -1e-307
      inclusivement pour les nombres négatifs, entre 1e-307 et
      9.99999999999999e+307 inclusivement pour les nombres positifs.

   Un nombre comportant plus de 15 chiffres significatifs sera arrondi
   au nombre à 15 chiffres significatifs le plus proche, conformément
   à l’algorithme "round to nearest, ties to even" de la norme IEEE 754
   [IEEE754].

   Cela signifie que les entiers de 0 à 999999999999999 (10^15-1)
   sont représentables sans problème dans JNTP, mais qu’au delà il
   y aura perte d’information. Par exemple, les six nombres de
   1000000000000000 (10^15) à 1000000000000005 (10^15+5) seront
   tous représentés par le premier d’entre eux.

   Après un éventuel arrondi à 15 chiffres significatifs, le nombre
   sera remplacé par -0 s’il est compris entre -1e-307 et -0, par 0
   s’il est compris entre 0 et 1e-307. Mais si sa valeur absolue est
   supérieure à 9.99999999999999e+307, il sera remplacé par la valeur
   null, puisque JSON ne connaît pas d’Infinity ni de NaN.

3. Valeur propre, représentation, et représentation canonique

   Le format JNTP, tout comme le format JSON, définit une représentation
   sous la forme de chaînes de caractères imprimables des différentes
   valeurs possibles.

   Par exemple, l’entier 125 est représenté par les trois caractères
   "1", "2" et "5". On dit que la chaîne de trois caractères 125 est
   une représentation de la valeur propre 125.

   De la même manière, la chaîne de treize caractères "\tHello\r\n"
   (avec les guillemets) est la représentation d’une chaîne de huit
   caractères : une tabulation, les caractères "H", "e", "l", "l",
   "o", un retour chariot, et un saut de ligne. C’est cette chaîne
   de huit caractères que nous appelons la valeur propre de la
   représentation "\tHello\r\n".

   Une représentation n’est généralement pas unique. Par exemple,
   les chaînes de caractères suivantes sont trois représentations
   différentes de la même valeur propre de type ‘string’ :
      "\tHello\r\n"
      "\u0009Hello\u000d\u000a"
      "\u0009\u0048\u0065\u006c\u006c\u006f\u000d\u000a"

   De même, les caractères blancs et l’ordre des clés n’étant pas
   significatifs dans un objet, voici deux représentations
   différentes de la même valeur propre de type ‘object’ :
      {
         "one" : 1,
         "two" : 2,
         "three" : 3
      }
      {"one":1,"three":3,"two":2}

3.1. Représentation canonique

   Parmi les différentes représentations possibles d’une valeur propre,
   on en choisit une et une seule que l’on appelle la représentation
   canonique. Pour qu’une représentation soit dite canonique, elle DOIT
   respecter toutes les règles des sections 3.2 à 3.6.

3.2. Représentation canonique d’une des trois valeurs littérales

   Dans la section 3 de JSON [RFC7159] sont définies trois valeurs
   littérales :

      false null true

   Ces trois représentations sont canoniques puisque chacune est unique.

3.3. Représentation canonique d’une chaîne de caractères

   La représentation des chaînes est définie dans la section 7 de
   JSON [RFC7159]. Il y est précisé que tout caractère Unicode peut
   être placé à l’intérieur des guillemets, sauf ceux qui doivent
   être echappés : le guillemet, la barre oblique inversée, et les
   caractères de commande (U+000 à U+001F). Sont aussi indiquées une
   séquence d’échappement courte pour les caractères spéciaux les plus
   fréquents, et la séquence d’échappement générale valable pour tous
   les caractères.

   Dans le but de choisir la représentation la plus lisible et la plus
   courte possible, voici le choix qui est fait pour chaque caractère
   lors de la mise d’une chaîne sous forme canonique. Noter que ce
   choix correspond au résultat de la fonction JSON.stringify telle
   que définie dans [ECMA-262].

   a) Les caractères qui DOIVENT être échappés le sont avec la
      séquence d’échappement courte s’ils en ont une. Il s’agit des
      sept caractères suivants.

                %x5C.22          ; \"    quotation mark U+0022
                %x5C.5C          ; \\    reverse solidus U+005C
                %x5C.62          ; \b    backspace       U+0008
                %x5C.66          ; \f    form feed       U+000C
                %x5C.6E          ; \n    line feed       U+000A
                %x5C.72          ; \r    carriage return U+000D
                %x5C.74          ; \t    tab             U+0009

      Noter que la barre oblique / (U+002F) n’en fait pas partie bien
      qu’elle possède une séquence d’échappement courte \/, puisqu’elle
      ne fait pas partie des caractères que l’on DOIT échapper.

   b) Les caractères qui DOIVENT être échappés, et qui n’ont pas de
      séquence d’échappement courte, le sont avec la séquence
      d’échappement générale. Lorsqu’un chiffre hexadécimal est une
      lettre de A à F celle-ci DOIT être mise en minuscule (a à f).

                %x5C.75 4hexdig ; \uxxxx                U+XXXX

       avec

                hexdig = DIGIT / %x61-66   ; 0-9 or lowercase a-f

      Cette syntaxe concerne tous les caractères de commande entre
      U+0000 et U+001F qui ne sont pas déjà traités dans la partie (a)
      ci-dessus.

   c) Dans tous les autres cas, les caractères sont placés directement
      entre les guillemets sans être échappés.

   Noter que ceci ne tient absolument pas compte des équivalences de
   caractères Unicode. Deux représentations Unicode différentes d’un
   même caractère, par exemple l’un en forme précomposée et un autre
   en forme décomposée, donneront deux valeurs JNTP différentes, même
   sous forme canonique.

3.4. Représentation canonique d’un nombre

   Avec les restrictions indiquées dans la section 2.2, un nombre mis
   sous forme canonique aura la représentation normalisée dans la
   section 9.8.1 "ToString Applied to the Number Type" de la norme
   "ECMAScript Language Specification Edition 5.1" [ECMA-262].

   Il respecte la grammaire suivante.

      number = [ minus ] unsigned

      unsigned = ( zero /   ; 0
             u-tiny    /   ; 1e-307          .. 9.99999999999999e-7
             u-small    /   ; 0.000001         .. 0.999999999999999
             u-medium   /   ; 1                .. 999999999999999
             u-large    /   ; 1000000000000000 .. 999999999999999000000
             u-huge )      ; 1e+21            .. 9.99999999999999e+307

      decimal-point = %x2E                ; .

      digit1-9 = %x31-39                  ; 1 .. 9

      e = %x65                            ; lowercase e

      e-minus-digits = digit1-9 *2DIGIT   : 7 .. 307

      e-plus-digits = digit1-9 1*2DIGIT   ; 21 .. 307

      frac14 = decimal-point *13DIGIT digit1-9

      int15 = digit1-9 *14DIGIT

      minus = %x2D                        ; –

      normalized = digit1-9 [ frac14 ]

      plus = %x2B                         ; +

      run15 = digit1-9 [ *13DIGIT digit1-9 ]

      u-huge = normalized e plus e-plus-digits

      u-large = digit1-9 14DIGIT 1*6zero

      u-medium = int15 [ frac14 ]         ; maximum 15 digits altogether

      u-small = zero decimal-point *5zero run15

      u-tiny = normalized e minus e-minus-digits

      zero = %x30                         ; 0

   Voici une liste d’exemples de nombres positifs mis sous forme
   canonique. Ces exemples sont ordonnés, et s’il n’y a pas de ligne
   de points de suspension "…" entre deux exemples cela signifie
   qu’il n’existe aucun nombre JNTP valide entre les deux. Chacun de
   ces nombres précédé d’un signe moins "-" reste un nombre sous forme
   canonique.

      0                            ; zero
      1e-307                      ; first tiny number
      1.00000000000001e-307       ; second tiny number
      1.00000000000002e-307       ; third tiny number
       …
      1.1e-307
       …
      9.99999999999998e-307
      9.99999999999999e-307
      1e-306
      1.00000000000001e-306
       …
      9.99999999999999e-7          ; last tiny number
      0.000001                     ; first small number
      0.00000100000000000001       ; second small number
       …
      0.00000999999999999999
      0.00001
      0.0000100000000000001
       …
      0.999999999999999            ; last small number
      1                            ; first medium number
      1.00000000000001             ; second medium number
       …
      3.14159265358979
       …
      3.1416
       …
      999999999999999             ; last medium number
      1000000000000000             ; first large number
      1000000000000010             ; second large number
       …
      9999999999999990
      10000000000000000
      10000000000000100
       …
      999999999999999000000       ; last large number
      1e+21                        ; first huge number
      1.00000000000001             ; second huge number
       …
      9.99999999999999e+307       ; last huge number

3.5. Représentation canonique d’un tableau

   La mise d’un tableau sous forme canonique se fait en deux étapes.

   a) Mise sous forme canonique de chaque élément du tableau.

   b) Suppression de tous les caractères blancs non significatifs
      (espaces, tabs, sauts de ligne et retours chariot) autour des
      caractères "[", "]" et "," encadrant ou séparant les valeurs
      du tableau.

   Bien entendu, cette décomposition en deux étapes n’est qu’une
   manière de présenter les choses et nullement une contrainte
   d’implémentation. Il est tout à fait possible de mener les deux
   étapes en parallèle pourvu que le résultat n’en soit pas changé.

3.6. Représentation canonique d’un objet

   La mise d’un objet sous forme canonique se fait en trois étapes.

   a) Mise sous forme canonique de chaque clé et de chaque valeur
      de l’objet.

   b) Suppression de tous les caractères blancs non significatifs
      (espaces, tabs, sauts de ligne et retours chariot) autour des
      caractères "{", "}", ":" et "," encadrant ou séparant les clés
      et les valeurs de l’objet.

   c) Tri des clés selon l’ordre lexicographique. Du fait que les
      caractères autorisés dans une clé pour un objet JNTP sont
      limités à un sous-ensemble de US-ASCII [RFC20], il ne sera
      généralement pas nécessaire de se soucier du charset utilisé.
      En effet, le tri donnera le même résultat avec UTF-8, UTF-16 BE
      ou LE (big endian ou little endian), ou avec tous les jeux 8-bits
      compatibles avec US-ASCII.

   Pour mémoire, voici l’ordre des caractères que l’on peut trouver dans
   une clé :
   #-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz

   Bien entendu, cette décomposition en trois étapes n’est qu’une
   manière de présenter les choses et nullement une contrainte
   d’implémentation. Par exemple, il est tout à fait possible de
   mener les étapes (a) et (b) en parallèle pourvu que le résultat
   n’en soit pas changé.

4. Manipulations sur des valeurs et des objets JNTP

4.1. Hachage d’une chaîne de caractères

   Un objet JNTP pouvant devenir très volumineux, en particulier s’il
   comporte des chaînes de caractères représentant des objets binaires,
   il est parfois souhaitable de remplacer temporairement une chaîne
   de caractères par une "empreinte" plus courte.

   Pour cela, la valeur propre de la chaîne de caractères est d’abord
   convertie en UTF-8 si ce n’est pas déjà le cas, puis on calcule
   l’empreinte SHA-1 du résultat considéré comme une chaîne d’octets
   (séquences de 8 bits). Le condensé obtenu (de 160 bits, soit 20
   octets) est alors codé en base64url, ce qui donne une chaîne de
   27 caractères pris parmi [-_A-Za-z0-9] (le caractère de complément
   "=" est ignoré puisque la longueur du condensat est toujours la
   même).

   Cette chaîne de 27 caractères est appelée le résultat du hachage
   de la chaîne de caractères initiale.

         hash_result = hash_string(string_value)

4.2. Hachage d’un objet JNTP

   Un autre type de hachage est primordial dans JNTP, celui d’un
   objet complet. Il sera utilisé en particulier dans le calcul
   du Jid expliqué plus loin.

   Pour obtenir le hachage d’un objet JNTP, il faut au préalable
   hacher chacune des chaînes de caractères présentant les
   caractéristiques suivantes :
   a) c’est une valeur d’un couple clé/valeur dans l’objet JNTP, ou
      dans n’importe quel sous-objet à quelque niveau que ce soit ;
   b) la clé n’est pas précédée de la directive "#" indiquant que la
      valeur a déjà été hachée ;
   c) la longueur de la valeur propre en octets, une fois convertie
      en UTF-8 si ce n’est pas déjà le cas, est strictement supérieure
      à une valeur convenue d’avance et propre à cette opération de
      hachage : max_safe_length.

   Pour chacune de ces chaînes de caractères, la clé est remplacée par
   « "#" + clé » et la valeur de la chaîne par le résultat du hachage
   hash_string(valeur).

   Une fois ceci réalisé, l’objet JNTP est mis sous forme canonique
   (voir sections 3.1 et suivantes), puis sa représentation (considérée
   comme la valeur d’une chaîne de caractères) est hachée de la même
   manière que dans la section 4.1.

         hash_result = hash_object(object_value, max_safe_length)

   Attention, le choix de la valeur max_safe_length, qui est la longueur
   maximum des chaînes ne devant pas être hachées, est très important.

   En particulier, il ne faut pas re-hacher avec un max_safe_length
   plus grand un objet dont certaines valeurs auraient déjà été hachées
   avec un max_safe_length plus petit, car on risquerait alors que le
   résultat ne soit pas unique ; en revanche, re-hacher avec un
   max_safe_length plus petit est sans risque.

4.3. Chemin d’accès à une valeur dans un objet JNTP

   On définit le chemin d’une valeur contenue dans un objet JNTP par
   une chaîne de caractères qui contient la hiérarchie de toutes les
   clés parentes séparées entre elles par le caractère ".". Lorsque
   la valeur est incluse dans un tableau, le chemin est suffixé du
   caractère ":" suivi d’un entier qui identifie la position de la
   valeur dans le tableau, le premier élément étant indicé à 1.

   Exemple avec l’objet JNTP :
   {
"Name" : "Julien Arlandis",
"ProjetRFC_v0_12" : {
"name" : "Nemo",
"contributeurs" : ["Joe", "Jim", "Jack"],
"content" : "Ce document définit un nouveau protoc\
ole pour la diffusion de données sur un réseau déc\
entralisé sur internet"
}
   }

   "Name" désigne "Julien Arlandis",
   "ProjetRFC_v0_12" désigne
   {
"name" : "Nemo",
"contributeurs" : ["Joe", "Jim", "Jack"] ,
"content" : "Ce document définit un nouveau protoc\
ole pour la diffusion de données sur un réseau déc\
entralisé sur internet"
   },
   "ProjetRFC_v0_12.name" désigne "Nemo",
   "ProjetRFC_v0_12.contributeurs" désigne ["Joe", "Jim", "Jack"],
   "ProjetRFC_v0_12.contributeurs:1" désigne "Joe",
   "ProjetRFC_v0_12.contributeurs:2" désigne "Jim",
   "ProjetRFC_v0_12.contributeurs:3" désigne "Jack".
   "ProjetRFC_v0_12.content" désigne "Ce document déf\
   init un nouveau protocole pour la diffusion de don\
   nées sur un réseau décentralisé sur internet".

5. Format d’un paquet JNTP

   On appelle paquet JNTP l’objet de plus haut niveau géré par le
   protocole JNTP. Celui-ci contient les six paires clé/valeur
   suivantes.

   packet =
   {
"Jid": String,
"Route": Array of String,
"ID": Number,
"ServerSign": String,
"Data": Object,
"Meta": Object
   }

   Le sous-objet Data, quant à lui, contient au moins les cinq
   paires clé/valeur suivantes, mais il peut y en avoir d’autres.

   Data = {
"DataType" : String,
"DataID" : String,
"InjectionDate" : String,
"OriginServer" : String,
"ServerPublicKey" : Object
(…)
   }

   On rappelle que l’ordre des clés d’un objet JNTP, comme de tout
   objet JSON, n’a aucune importance.

5.1. Jid (String, obligatoire)

   Jid est la chaîne de caractères qui identifie un paquet sur le
   réseau.
   Jid = hash_object(Data, 1024) "@" OriginServer

   La fonction hash_object est décrite dans les sections 4.1 et 4.2.

   OriginServer désigne le FQDN du nœud émetteur du paquet, sa valeur
   doit être identique à Data.OriginServer.

   Exemple :

   Data = {
"Name" : "Julien Arlandis",
"ProjetRFC_v0_12" : {
"name" : "Nemo",
"contributeurs" : ["Joe", "Jim", "Jack"],
"content" : "Ce document définit un nouveau protoc\
ole pour la diffusion de données sur un réseau déc\
entralisé sur internet"
}
   }

   minifyPacket(Data) = ‘{"Name":"Julien Arlandis","ProjetRFC_v0.1\
   2":{"#content":"ec360492b691b586739f535d5bde051bbbc08b66","cont\
   r ibuteurs":["Joe","Jim","Jack"],"name":"Nemo"}}’
   (note de l’auteur : si l’on tient à conserver l’exemple, d’une part
   il faudra choisir les clés correspondant à ce qu’on a dit sur l’objet
   Data, d’autre part il faudra donner un nom à l’opération de hachages
   de clés suivi de la mise de l’objet sous forme canonique)

   Le Jid est calculé par le serveur.

5.2. Route (Array of String, obligatoire)

   La route liste dans un tableau les différents nœuds empruntés par un
   paquet, dans l’ordre (le plus ancien en premier, le plus récent en
   dernier). La Route est calculée par le serveur.

   "Route": ["nemo.example.org", "news.example.net"] signifie que le
   paquet est passé successivement par le serveur nemo.example.org
   puis news.example.net.

5.3. ID (Number, obligatoire)

   L’ID est un nombre entier positif qui identifie localement un paquet
   sur un serveur donné, l’ID est incrémenté chaque fois que le serveur
   insère un nouveau paquet dans sa base de données. Il est
   principalement utilisé comme un moyen de pointer les paquets.
   Attention, cet entier ne DEVRAIT pas dépasser 999999999999999, et
   à partir de 10^15 on ne peut plus utiliser qu’un entier sur 10
   jusqu’à 10^16 (voir section 2.2).

5.4. ServerSign (String, obligatoire)

   Ce champ constitue la signature numérique qui garantit que le paquet
   a bien été émis par le serveur mentionné dans la partie droite du
   Jid réservé au nom de domaine du serveur.
   ServerSign = chiffrementAsymétrique(Jid, PrivateKey) où PrivateKey
   désigne la clé privée du serveur.
   On peut donc vérifier que Jid = chiffrementAsymétrique(ServerSign,
   PublicKey).
   Ce champ est calculé par le serveur.

5.5. Data.DataType (String, obligatoire)

   Identifie le format de données de la Data.
   La structure de la Data à l’exception des clés Data.DataID,
   Data.InjectionDate, Data.OriginServer et Data.ServerPublicKey est
   entièrement définie par le format de données désigné par
   Data.DataType, cf. "titre à donner" [RFCYYYY].

5.6. Data.DataID (String, facultative)

   Cette clé permet de désigner des objets identiques qui ne peuvent
   pas être identifiés par un même Jid faute d’une représentation
   unique de la Data. Par exemple il peut arriver que des données
   générées en dehors de JNTP soient appelées à être injectées sur JNTP
   sous des formes différentes et par des passerelles différentes sans
   qu’il ne soit possible d’assurer l’unicité du Jid pour ces objets.
   La clé Data.DataID permet à la fois de les identifier et d’empêcher
   leur redondance au sein d’un réseau JNTP.
   La valeur de Data.DataID doit être unique sur l’ensemble du réseau
   pour un DataType bien déterminé. La clé Data.DataID peut par
   construction du Jid (voir la fonction minifyPacket) contenir la même
   valeur que le Jid du paquet.

5.7. Data.InjectionDate (String, obligatoire)

   Contient la date au format UTC à laquelle le paquet a été émis sur
   le réseau JNTP.
   Data/InjectionDate = AAAA "-" MM "-" JJ "T" HH ":" MM ":" SS "Z"
   Ce champ est renseigné par le serveur.

5.8. Data.OriginServer (String, obligatoire)

   OriginServer désigne le FQDN du nœud émetteur du paquet. Ce FQDN
   doit disposer d’un enregistrement DNS A, AAAA ou CNAME sur le réseau
   internet.

5.9. Data.ServerPublicKey (Object, obligatoire)

   Contient la clé publique du serveur correspondant à la clé privée
   qui a servi à signer le paquet. Contient également des informations
   spécifiques comme les dates de validité.
   [Note de l’auteur : partie à détailler]

5.10. Meta (Object, facultatif)

   Cet objet contient les informations annexes à un paquet, il s’agit
   de valeurs précalculées qui ont pour objectif de fournir des
   informations utiles aux clients ou aux autres serveurs.
   Cet objet est susceptible de contenir des clés dont la description
   est fournie par le DataType du paquet.

6. References

6.1. Normative References

   [RFC20]    Cerf, V., "ASCII format for network interchange", RFC 20,
             October 1969, .

   [IEEE754] IEEE, "IEEE Standard for Floating-Point Arithmetic", IEEE
             Standard 754, August 2008,
             .

   [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
             Requirement Levels", BCP 14, RFC 2119, March 1997,
             .

   [RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
             Specifications: ABNF", STD 68, RFC 5234, January 2008,
             .

   [RFC7159] Bray T., Ed., "The JavaScript Object Notation (JSON) Data
             Interchange Format", RFC 7159, March 2014,
             .

   [RFCYYYY] Arlandis J. and O. Miakinen, "(titre à donner)",
             RFC YYYY, date.

   [RFCZZZZ] Arlandis J., "(titre à donner)", RFC ZZZZ, date.

   [UNICODE] The Unicode Consortium, "The Unicode Standard",
             .

6.2. Informative References

   [ECMA-262] Ecma International, "ECMAScript Language Specification
             Edition 5.1", Standard ECMA-262, June 2011,
             .

   [ECMA-404] Ecma International, "The JSON Data Interchange Format",
             Standard ECMA-404, October 2013,
             .

   [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
             Extensions (MIME) Part One: Format of Internet Message
             Bodies", RFC 2045, November 1996,
             .

   [RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322,
             October 2008,
             .

A. Exemples de code

A.1. Normalisation d’un nombre

   Le code suivant, écrit en JavaScript, réalise simultanément deux
   choses sur la représentation d’un nombre :
   a) sa restriction aux valeurs valides conformément à la section 2.2,
   b) sa mise sous forme canonique conformément à la section 3.4.
   (note de l’auteur : je vais refaire son indentation)

function normalize_jntp_number(strnum)
{
/*
   * In this function, the variables n, k and s refer to the algorithm
   * in section 9.8.1 "ToString Applied to the Number Type" of the
   * "ECMAScript Language Specification – ECMA-262 Edition 5.1",
   * .
   *
   * The absolute value of the number ‘strnum’ shall be represented
   * by s * 10^(n-k), where k is the number of digits in the decimal
   * representation of s, and k is as small as possible.
   *
   * This code is illustrated by an example :
   *   strnum = "-0.031415999999999971000e+2"
   */
strnum = "" + strnum;                  // Ensure strnum is a string

var re = /^([-+]?)([0-9]+)(?:[.]([0-9]+))?(?:[eE]([-+]?[0-9]+))?$/;
var match = re.exec(strnum);
if (match == null) return null;

var sign = (match[1] == "-") ? "-" : "";
var s = match[3] ? match[2] + match[3] : match[2];
var k = s.length;
var n = match[4] ? +match[4] + match[2].length : match[2].length;

/*
   * In the example:
   *   sign = "-", s = "0031415999999999971000", k = 22, n = 3
   */

re = /^(0*)([0-9]+?)0*$/;
match = re.exec(s);
if (match == null) return null;       // should not occur

s = match[2];
k = s.length;
n = n – match[1].length;

/*
   * In the example:
   *   sign = "-", s = "31415999999999971", k = 17, n = 1
   */

if (s == "0") return sign + s;         // either "0" or "-0"

/*
   * The mantissa s shall be restricted to 15 digits maximum, this
   * will be performed by "rounding to nearest, ties to even".
   */
if (k 15) {                         // maximum length for s
    var round_up;                        // rounding direction
    var lastdigit = +(s.charAt(15));    // 7 in the example
    if (lastdigit < 5) {       round_up = false;                  // simple truncation     } else if (lastdigit 5) {       round_up = true;                   // shall increment 14th digit     } else if (k 16) {       round_up = true;                   // shall increment 14th digit     } else {       var prevdigit = +(s.charAt(14));       round_up = ((prevdigit % 2) == 1); // ties to even     }     s = s.substring(0, 15);     k = 15;     /*     * In the example:     *   sign = "-", s = "314159999999999", k = 15, n = 1     */     if (round_up) {       while ((k 0) && (s.charAt(k-1) == "9")) {        k = k - 1;        s = s.substring(0, k);       }       /*        * In the example:        *   sign = "-", s = "31415", k = 5, n = 1        */       if (k 0) {        lastdigit = +(s.charAt(k-1));      // 0 .. 8        lastdigit = lastdigit + 1;         // 1 .. 9        s = s.substring(0, k-1) + lastdigit;       } else {        // 0.999999999999999 10^n -1 10^n = 0.1 10^(n+1)        s = "1";        k = 1;        n = n + 1;       }       /*        * In the example:        *   sign = "-", s = "31416", k = 5, n = 1        */     } else {       /*        * Assertion : k is always 0 since the first digit is        * not zero        */       while (s.charAt(k-1) == "0") {        k = k - 1;        s = s.substring(0, k);       }     } } // Assertion : 1 <= k <= 15 if (abs(n-1) 307) {     // number greater than 9.99999999999999e+307 or less than 1e-307     if (n 0)       return null;     else       return sign + "0"; } // Step 6 in "9.8.1 - ToString Applied to the Number Type" if ((k <= n) && (n <= 21)) {     while (k < n) {       s = s + "0";       k = k + 1;     }     return sign + s; } // Step 7 in "9.8.1 - ToString Applied to the Number Type" if ((0 < n) && (n <= 21)) {     // Assertion : 0 < n < k     return sign + s.substring(0, n) + "." + s.substring(n, k); } // Step 8 in "9.8.1 - ToString Applied to the Number Type" if ((-6 < n) && (n <= 0)) {     // 0 <= -n <= 5     return sign + "0." + "00000".substring(0, -n) + s; } // Assertion : n <= -6 or n >= 22

// Step 9 in "9.8.1 – ToString Applied to the Number Type"
if (k == 1) {
    return sign + s + ((n 0) ? "e+" : "e-") + abs(n-1);
}

// Step 10 in "9.8.1 – ToString Applied to the Number Type"
return sign + s.charAt(0) + "." + s.substring(1) +
                      ((n 0) ? "e+" : "e-") + abs(n-1);
}