Aller au contenu
Condorcet.vote Alpha
← Documentation technique

Registre public

Ce que chaque élection rend public, quel que soit le moyen qui le transporte, et ce que n'importe qui peut en vérifier sans faire confiance à la plateforme.

Le registre est la trace vérifiable de l'élection. La plateforme est un tiers de confiance au moment du vote ; tout ce qu'elle a fait est ensuite contrôlable à partir du registre publié seul. Cette page décrit son contenu, indépendamment de son transport : la blockchain n'est qu'un des moyens de le distribuer, celui qui en rend l'intégrité et l'immuabilité contrôlables par tous.

Protocole v1

Contenu

Cinq pièces, deux côtés non reliables.

Une définition et des anneaux, communs à toute l'élection, puis deux registres délibérément séparés : l'émargement dit qui a pris part, le registre des bulletins dit ce qui a été voté, avec sa preuve cryptographique, sans trace de qui ni de quand. Le résultat s'en déduit.

  • Contexte

    Définition de l'élection

    Titre, organisateur, type, sièges, candidats, règles de bulletin et options de vie privée, gelés avant le premier bulletin.

    À l'ouverture · bloc configuration

  • Contexte

    Anneaux

    La liste complète des clés publiques autorisées à signer, anneau par anneau, avec l'empreinte de chaque anneau.

    À l'ouverture, puis par anneau d'urgence · blocs rings

  • Côté émargement

    Registre d'émargement

    Une ligne par votant, sous un identifiant aléatoire : a voté ou non, dans quel anneau, combien de clés reçues, quel poids. Pseudonyme par défaut.

    À la clôture, en un seul instantané · bloc closure

  • Côté bulletins

    Bulletins signés

    Chaque bulletin tel que signé, octet pour octet, avec sa signature en anneau et son image de clé, sans identité ni horodatage.

    Pendant le vote, par lots d'au moins 600 · blocs votes

  • Calcul

    Résultat publié

    Le classement officiel, avec la méthode et les versions de calcul enregistrées, et les bulletins au format CEF. Ce n'est jamais un bloc : il se recalcule.

    À la publication par l'organisateur · page des résultats

  • Hors registre

    Jamais publié

    Les horodatages, l'ordre d'arrivée, la correspondance entre identifiant et identité (sauf option nominative), la présentation cosmétique : logo, photos, message de remerciement.

    Ni sur la page, ni dans un bloc

Définition & anneaux

Ce qui est gelé avant le premier bulletin.

La définition est figée au lancement de l'élection ; chaque anneau l'est à sa création. Ni l'une ni les autres ne changent ensuite : chaque bulletin se vérifie contre la définition et l'anneau publiés.

Définition de l'élection

protocol_version entier
La version du protocole, 1 aujourd'hui, liée à l'élection pour toujours.
election_id UUID v4
L'identifiant de l'élection, repris dans chaque bulletin signé et dans chaque vérification de signature.
title, description?, organizer_name chaînes
Contexte informatif publié en clair, jamais une entrée du dépouillement.
election_type, seats preferential | fptp, entier ≥ 1
Classement ou choix unique ; nombre de sièges, donc de candidats élus en tête du classement.
candidates[].label tableau
Les étiquettes des candidats, seul identifiant, triées par étiquette.
ballot_rules objet
Les paramètres du bulletin (égalités, classement partiel, vote blanc, classement complet), dont les contraintes de dépouillement se déduisent par une règle documentée.
non_anonymous_voting, nominative_participation, weighted_voting booléens
Les options de vie privée et de pondération, désactivées par défaut. Le vote non anonyme impose l'émargement nominatif.
max_ring_size, initial_electoral_roll_size entiers
Le plafond de taille d'anneau (600 aujourd'hui) et la taille de la liste électorale à l'ouverture.

Le détail champ par champ, avec voter_access_mode et enrolment_mandatory, figure dans la spécification de la blockchain. La méthode de Condorcet ne fait pas partie de la définition : elle est publiée avec le résultat.

Anneaux

ring_id UUID
L'anneau contre lequel un bulletin est signé ; chaque bulletin le nomme.
public_keys[] pk_<64 hexa>_<8 hexa>
Toutes les clés publiques de l'anneau, uniques, triées par ordre croissant, au plus max_ring_size.
ring_digest ring_<64 hexa>_<8 hexa>
L'empreinte canonique de l'ensemble des membres, indépendante de l'ordre, recalculable à partir des clés.

L'anonymat d'un bulletin, c'est exactement l'anneau sous lequel il est signé : une plateforme qui servirait à un votant un anneau différent d'un seul membre pourrait reconnaître son bulletin. La page de vote calcule l'empreinte à partir de l'anneau reçu (elle ne la reçoit jamais de la plateforme), l'affiche avant la signature et l'inscrit dans le reçu ; le votant la compare à la valeur publiée ici pour tous. C'est une détection, pas une prévention.

Un anneau d'urgence, créé pendant le vote si la liste s'agrandit, est publié à sa création. Chaque anneau se télécharge en JSON depuis la page du registre, avec son empreinte et ses clés dans le même ordre que dans son bloc.

Émargement

Qui a pris part, publié une seule fois.

Le registre d'émargement est publié en un unique instantané, dans le bloc de clôture, quand la liste est définitive. Pendant le vote, la page du registre n'en montre rien : aucune ligne de participation ne partage une fenêtre de publication avec un bulletin.

Une ligne par votant

voter_id UUID v4 aléatoire
Le seul identifiant de la ligne ; lignes triées par voter_id. Identique dans toutes les élections d'un même groupe.
key_provisioning_mode server_generated | organizer_imported | voter_enrolled
L'origine de la clé : générée par la plateforme, importée par l'organisateur, ou apportée par le votant.
has_voted booléen
A voté ou non.
ring_id UUID ou null
L'anneau dans lequel le votant a voté, null s'il n'a pas voté : le lien votant → anneau du contrôle par anneau.
distribution_count entier ≥ 0
Le nombre de clés de vote distribuées : 3 au plus par défaut, davantage seulement si l'organisateur en accorde, ce qui reste visible. Les distributions ne sont pas détaillées.
weight entier ≥ 1
Le poids (tantièmes), toujours présent, 1 sans vote pondéré : la valeur contre laquelle se vérifie le poids signé dans le bulletin.

La liste de clôture comprend les votants ajoutés pendant le vote : sa taille moins initial_electoral_roll_size en donne le nombre, jamais lesquels. Le bloc de clôture porte aussi les totaux : blocs, bulletins, anneaux, votants, poids exprimé.

Émargement nominatif : une option

Désactivé par défaut, l'organisateur peut l'activer au lancement, les votants en étant avertis ; le vote non anonyme l'impose. Seules les lignes des votants qui ont voté reçoivent alors deux champs de plus.

voter_name chaîne
Le nom en clair, tel que fourni par l'organisateur à l'import.
email_digest 64 caractères hexa
SHA3-256(election_id ‖ adresse e-mail normalisée), hexa minuscule : une empreinte propre à l'élection.
  • Les abstentionnistes ne sont jamais nommés. Leur ligne reste pseudonyme : l'option révèle qui a voté, jamais qui s'est abstenu.
  • Une divulgation de participation, pas de bulletin. Seule, elle relie un nom au fait d'avoir voté, jamais à un bulletin. Avec le vote non anonyme, qui inscrit l'identifiant de votant dans le bulletin signé, le lien devient bulletin → identifiant → nom.
  • Une empreinte faible, assumée. Le sel (election_id) est public et une adresse e-mail se devine : qui détient une adresse peut confirmer la participation de son titulaire et la relier d'une élection à l'autre. C'est un outil de contrôle de la liste, pas une protection ; cela reste une donnée personnelle.
Bulletins

Ce qui a été voté, sans qui ni quand.

Un enregistrement par bulletin, trié par image de clé : un ordre déterministe, tiré du contenu, sans rapport avec l'ordre d'arrivée.

Un enregistrement par bulletin

ring_id UUID
L'anneau dont les clés vérifient la signature.
payload chaîne JSON
La charge utile signée, telle quelle, octet pour octet : version, élection, expression du bulletin, poids, et l'identifiant de votant en vote non anonyme.
signature blsag_…
La signature en anneau (bLSAG) de la charge utile.
key_image ki_…
L'image de clé : une même clé donne toujours la même image dans une élection, sans révéler laquelle des clés de l'anneau a signé.
Spécification du bulletin signé
  • Publication par lots. Les bulletins sont publiés par lots d'au moins 600, selon une fenêtre de temps aléatoire ; un lot trop petit attend le suivant. Tout est publié à la clôture, le dernier lot pouvant compter moins de 600 bulletins : une élection de moins de 600 votants publie donc ses bulletins à la clôture.
  • Une seule règle pour la page et la chaîne. La page du registre et la blockchain lisent le même indicateur, is_chain_published : elles montrent toujours exactement le même ensemble de bulletins. Pendant le vote, la page affiche le nombre de bulletins reçus en attente de publication, sans leur contenu.
  • Retrouver son bulletin avant publication. La recherche par image de clé (envoi POST, limité en fréquence) trouve aussi un bulletin reçu mais pas encore publié. Une image de clé ne se devine pas : seul le détenteur du reçu peut la soumettre. La liste publique, elle, ne montre que les bulletins publiés.
  • Une page par bulletin publié. Charge utile, signature, image de clé et empreinte de son anneau. L'identifiant de bulletin qu'affiche la page est un UUID v4 aléatoire ; il ne figure pas dans les blocs.
Calendrier

Quand chaque pièce apparaît.

Rien n'est public avant l'ouverture du vote. Ensuite, le registre ne fait que s'allonger, jusqu'à la clôture qui le termine.

Selon l'état de l'élection

Draft, Enrolment, Opening Préparation
Rien de public. À Opening, la définition et les anneaux de lancement sont gelés et scellés.
Open Vote ouvert
La page du registre est en ligne : définition, anneaux, bulletins publiés par lots, nombre de bulletins en attente, recherche par image de clé. Un anneau d'urgence apparaît à sa création. Pas d'émargement.
Closed Vote clos
Le dernier lot de bulletins, puis le bloc de clôture : émargement complet et totaux. Aucun bloc ne peut lui succéder.
Published Résultat publié
L'organisateur publie le résultat : page des résultats et téléchargement CEF.
Archived Archivée
Le registre reste consultable en lecture seule ; le résultat n'est plus affiché publiquement.
Cancelled Annulée
Toutes les vues publiques sont retirées, la page du registre l'annonce. Aucun bloc de clôture n'est émis : les blocs déjà publiés restent valides, la chaîne s'arrête.

Le résultat publié

  • Jamais un bloc. Le résultat se recalcule à partir de la définition et des bulletins publiés ; il n'est pas une donnée de la chaîne.
  • Méthode et versions enregistrées. Le résultat enregistre la méthode utilisée, la version de la bibliothèque CondorcetPHP et la version du contrat de dépouillement, pour qu'un recompte rejoue exactement la même sémantique. La page des résultats affiche la méthode et la version de la bibliothèque.
  • Les bulletins au format CEF. Téléchargeables depuis la page des résultats : une commodité, reconstructible à partir du registre seul, qu'un vérificateur peut régénérer pour comparer.
  • Les élus. Les seats premières places du classement recalculé, rien de plus.
Spécification du dépouillement & recompte
Page & blockchain

Les mêmes données, deux lectures.

La page du registre est la vue principale, paginée et consultable, des données publiées ; elle n'est pas immuable. La blockchain est un moyen de distribuer ces mêmes données : des fichiers JSON chaînés par empreinte et signés par la plateforme, que chacun peut télécharger et conserver. La page l'intègre comme une sous-section.

Adresses publiques par élection

/elections/{election}/register
La page du registre : état de l'élection, compteurs, émargement, anneaux, recherche, bulletins, blockchain.
POST /elections/{election}/register/lookup
La recherche d'un bulletin par image de clé, limitée en fréquence ; l'image de clé n'apparaît jamais dans une URL.
/elections/{election}/register/ballots/{ballot}
Le détail d'un bulletin publié.
/elections/{election}/register/rings/{ring}/keys
Un anneau en JSON : election_id, ring_id, ring_number, ring_digest, public_keys.
/elections/{election}/results
Le résultat, à l'état Published seulement.
/elections/{election}/results/ballots.cef
Les bulletins au format CEF, sous la même condition.
/elections/{election}/chain
Le manifeste de la blockchain, qui mène à chaque bloc et à ses fichiers annexes.

Ces adresses n'ont pas de préfixe de langue et ne sont pas indexées par les moteurs de recherche. Elles existent tant que l'élection a un registre public, de Open à Archived.

Ce que la blockchain ajoute

  • Les mêmes données. Quatre types de blocs (configuration, rings, votes, closure) qui portent exactement le contenu décrit sur cette page.
  • L'intégrité. Chaque bloc porte l'empreinte SHA3-512 du précédent et une signature détachée de la plateforme : une modification rétroactive casse la chaîne pour tout observateur ultérieur.
  • L'immuabilité, à vérifier. La signature prouve l'origine, pas l'immuabilité : la plateforme détient sa clé. Ce sont les copies conservées par des tiers, et l'ancrage dans Bitcoin par OpenTimestamps qui date les octets de chaque bloc, qui rendent une réécriture détectable.
  • Sans API. Des fichiers statiques, mis en cache, archivables, que chacun peut reproduire en miroir.
Spécification de la blockchain
Vérifications

Ce que chacun peut contrôler, à partir du registre seul.

Sans faire confiance à la plateforme, avec les seules données publiées.

  1. 1 Chaque bulletin est signé par un membre de son anneau. Rejouer la vérification de la signature en anneau sur (charge utile, identifiant d'élection, signature, image de clé, anneau) pour chaque bulletin.
  2. 2 Une clé, un bulletin. Toutes les images de clé de l'élection sont distinctes : aucune clé n'a servi deux fois. Comme un votant peut avoir reçu plusieurs clés, c'est avec les contrôles 3 et 4 que cela donne un bulletin par votant.
  3. 3 Aucun bulletin ajouté dans un anneau. Pour chaque anneau, le nombre de bulletins est égal au nombre de lignes d'émargement dont l'anneau de vote est celui-là.
  4. 4 Pas plus de bulletins que de votants. Le total des bulletins ne dépasse pas le nombre de lignes has_voted : c'est la borne qui compte contre le bourrage. En vote pondéré, les poids signés et les poids émargés des votants forment le même multiensemble, de somme voted_weight.
  5. 5 Le recompte. Sérialiser les charges utiles en CEF et les dépouiller avec CondorcetPHP ou toute implémentation CEF, avec les contraintes déduites des règles de bulletin publiées : on retrouve le classement et les décomptes exprimés, blancs et nuls.
  6. 6 Les élus. Lire les seats premières places du classement recalculé.

Ce que chaque votant peut contrôler en plus

  • Sa ligne d'émargement. Par son identifiant de votant : a voté ou non, nombre de clés reçues. Une activité inventée à son nom se voit.
  • Son anneau. L'empreinte d'anneau de son reçu, calculée par son navigateur, doit être égale à celle que publie le registre.
  • Son bulletin. Avec l'image de clé de son reçu, il retrouve son bulletin et en vérifie le contenu octet pour octet, même avant sa publication.

La garantie centrale est la liste figée des bulletins signés : contrôles 1 à 4, plus l'intégrité de la chaîne. Le recompte est un contrôle croisé ; un écart de résultat entre implémentations serait un défaut d'un logiciel de calcul, pas un défaut de vérifiabilité.

Procédure de vérification
Limites

Ce que le registre ne dit pas.

Ce qu'il tait par conception, et ce qu'il ne peut pas prouver ou laisse entrevoir.

Ce qu'il ne révèle pas

  • Aucun horodatage. Aucun enregistrement publié ne porte de date ; les dates techniques restent dans la base de données.
  • Aucun ordre d'arrivée. Bulletins triés par image de clé, émargement par identifiant de votant : deux clés de tri différentes, sans rapport avec la chronologie.
  • Aucun lien entre votant et bulletin. L'émargement n'est publié qu'à la clôture, jamais par fenêtre : ses lignes ne peuvent pas être alignées dans le temps avec les bulletins. Seul le vote non anonyme établit ce lien, par choix de l'organisateur.
  • Aucune identité, par défaut. Sans l'option nominative, le registre ne contient aucune donnée nominative ; la correspondance entre identifiant et identité n'est connue que de la plateforme et de l'organisateur.
  • Aucune présentation cosmétique. Logo, photos des candidats, message de remerciement : ni publiés, ni hachés.

Ce qu'il ne peut pas prouver, ou laisse voir

  • Le moment du vote. Que le serveur n'a pas observé un votant pendant qu'il votait : la plateforme est un tiers de confiance à ce moment-là.
  • Une participation inventée. Qu'une ligne « a voté » n'a pas été fabriquée pour un absent : seul ce votant peut le constater.
  • Qui a signé dans l'anneau. Par construction.
  • Un ordre grossier. Les blocs de votes se suivent : tout bulletin d'un bloc a été émis avant le scellement du suivant, à la granularité d'au moins 600 bulletins. Un anneau d'urgence, publié plus tard, indique de même que ses bulletins sont plus tardifs.
  • Les petits anneaux et les poids rares. Dans un anneau où un seul votant a voté, son identifiant est relié à son bulletin, et son nom avec l'option nominative. L'organisateur, qui connaît le nom derrière chaque identifiant, peut faire ce rapprochement quel que soit le mode de clés. En vote pondéré anonyme, un poids presque unique désigne son votant.
  • Les inscrits sans clé. Dans une élection où les votants doivent apporter leur clé, un inscrit qui n'en a déposé aucune ne peut pas voter et n'apparaît pas, aujourd'hui, dans l'émargement publié.
  • L'immuabilité de la page. La page du registre peut changer ; l'immuabilité se vérifie sur la blockchain, dans la mesure où des tiers en ont conservé des copies.