Aller au contenu
Condorcet.vote Alpha
← Documentation technique

Procédure de vérification

Deux chemins pour contrôler une élection sans faire confiance à la plateforme : le registre publié suffit à vérifier les bulletins et le résultat ; la blockchain y ajoute l'intégrité et l'immuabilité de ce registre.

Le second chemin englobe le premier. Chaque contrôle dit ce qu'il prouve et renvoie à la spécification sur laquelle il repose ; les outils sont standards ou ouverts : CryptoVote, CondorcetPHP, sq, openssl, ots.

Protocole v1

Chemin 1 · Registre seul

Les bulletins et le résultat, depuis le registre.

Le registre public d'une élection publie sa définition, ses anneaux, ses bulletins signés et, à la clôture, son registre d'émargement. Ces contrôles les prennent tels qu'ils sont servis, sur la page du registre ou dans les fichiers des blocs. Les contrôles de participation attendent la clôture : l'émargement n'est publié qu'une fois, dans le bloc closure.

  1. 1

    Chaque bulletin est authentique.

    Pour chaque bulletin, exécuter verify_vote (opération C de CryptoVote) sur la charge utile telle quelle, l'identifiant de l'élection, la signature, l'image de clé et les clés publiques de son anneau. Recalculer aussi l'empreinte de chaque anneau (ring_digest) à partir de ses public_keys et la comparer à celle publiée.

    Ce que cela prouve : Chaque bulletin a été signé par une clé de son anneau, sur ces octets exacts : un bulletin modifié, ou signé hors de l'anneau, ne vérifie pas.

    Repose sur Bulletin signé

  2. 2

    Une seule fois par clé.

    Toutes les images de clé (ki_…) sont distinctes au sein de l'élection. L'image de clé est propre au couple clé secrète-élection : deux bulletins signés avec la même clé portent la même image.

    Ce que cela prouve : Aucune clé n'a servi deux fois : un tel double vote serait publiquement manifeste.

    Repose sur Bulletin signé

  3. 3

    Chaque anneau correspond à ses votants.

    Pour chaque anneau R, le nombre de bulletins signés contre R est égal au nombre de lignes d'émargement dont l'anneau voté (ring_id) est R. La borne « bulletins ≤ clés de l'anneau » découle de l'unicité des images de clé.

    Ce que cela prouve : Les bulletins de chaque anneau se rattachent à des votants enregistrés comme ayant voté dans cet anneau.

    Repose sur Registre public

  4. 4

    Pas plus de bulletins que de votants.

    Le nombre total de bulletins ne dépasse pas le nombre de lignes has_voted du registre d'émargement. En vote pondéré, le multiensemble des poids signés dans les bulletins est égal au multiensemble des poids des lignes has_voted.

    Ce que cela prouve : C'est la borne qui empêche le bourrage : la plateforme ne peut publier ni plus de bulletins que de votants marqués comme ayant voté, ni un poids qu'aucun votant n'a reçu, sans qu'aucun bulletin soit relié à un votant.

    Repose sur Registre public

  5. 5

    Le résultat se recalcule.

    Convertir chaque charge utile publiée au format CEF, avec son poids signé en vote pondéré, et la soumettre à CondorcetPHP (ou à toute implémentation conforme CEF) avec les contraintes dérivées des règles de bulletin de la définition. Le résultat publié indique la méthode, la version de la bibliothèque et celle du contrat de dépouillement ; les élus sont les premiers du classement, autant que de sièges.

    Ce que cela prouve : Le classement et les décomptes annoncés (exprimés, blancs, nuls) sont ceux que donnent les bulletins publiés. Le cœur de la garantie reste la liste signée des bulletins : un écart entre implémentations serait un défaut de calcul, pas de vérifiabilité.

    Repose sur Dépouillement & recompte

  6. 6

    Chaque votant retrouve son bulletin.

    Avec son reçu (.condorcet_receipt), le votant cherche son image de clé sur la page du registre, qui trouve aussi un bulletin reçu mais pas encore publié, et compare le bulletin publié, octet par octet, à la charge utile signée du reçu. Il compare aussi le ring_digest du reçu, calculé par son propre navigateur, à celui publié pour l'anneau, et contrôle sa ligne d'émargement par son identifiant de vote.

    Ce que cela prouve : Son bulletin figure tel qu'il l'a signé, son anneau est bien celui publié pour tous, et aucune activité n'a été fabriquée sur sa ligne. À sa seule initiative, il peut aussi prouver à un tiers qu'un bulletin publié est le sien, ce qui révèle son vote.

    Repose sur Fichiers du votant Preuve de vote

Chemin 2 · Avec la blockchain

Intégrité et immuabilité, contrôlables par tous.

Le registre est aussi publié en blocs JSON chaînés, signés par la plateforme et ancrés dans Bitcoin. Sept contrôles, à partir des seuls fichiers publiés, établissent que ce registre est authentique, complet et inchangé ; le sixième y rejoue le chemin 1. La plateforme ne fournit pas de vérificateur : une auto-vérification par celui qui produit la chaîne n'ajouterait aucune confiance.

  1. 1

    Récupérer les fichiers.

    Le trousseau de certificats de la plateforme sur /.well-known/blockchain-signing-key, clés retirées et expirations comprises ; le manifeste de l'élection (/elections/{election}/chain) ; chaque bloc {n}.json, sa signature {n}.json.sig et sa preuve {n}.json.ots.

    Ce que cela prouve : Qu'aucun accès privilégié n'est nécessaire : ce sont des fichiers bruts, cachables et mirrorables, nommés avec l'identifiant de l'élection ; une copie détachée de son URL reste identifiable.

    Repose sur Clés de la plateforme Blockchain

  2. 2

    Vérifier chaque signature.

    Une commande par bloc, avec toute implémentation RFC 9580 : sq verify, car GnuPG ne vérifie pas les signatures OpenPGP v6. Les règles de validité standard rejettent une signature datée hors de la fenêtre de sa clé. En vérification stricte, exiger la notation domain@condorcet.vote = chain-block/v1 et une date de création égale au signed_at du manifeste.

    Ce que cela prouve : L'authenticité : chaque bloc a été produit par la plateforme et n'a pas changé d'un octet depuis sa signature. Pas, à elle seule, l'immuabilité (voir les limites).

    Repose sur Clés de la plateforme

  3. 3

    Contrôler le chaînage.

    Le bloc 0 est de type configuration, avec un previous_hash nul ; pour chaque bloc k > 0, le SHA3-512 du fichier k − 1 (openssl dgst -sha3-512) est égal au previous_hash du bloc k ; les block_number se suivent de 0 à n ; election_id est le même sur chaque bloc.

    Ce que cela prouve : L'ordre et la continuité de la chaîne : aucun bloc ne peut être retiré, inséré ou modifié sans rompre le chaînage de tous les suivants.

    Repose sur Blockchain

  4. 4

    Contrôler la clôture.

    Exactement un bloc closure, en dernier, rien après lui. Ses totals se recoupent avec la chaîne : block_count avec le nombre de blocs (clôture comprise), ballot_count avec les bulletins des blocs votes, ring_count avec les anneaux des blocs rings, voted_count et voted_weight avec les lignes has_voted de son registre d'émargement.

    Ce que cela prouve : La chaîne est complète : un bloc de clôture signé, au bout d'un chaînage continu, prouve qu'aucun bloc ne manque.

    Repose sur Blockchain

  5. 5

    Valider chaque bloc.

    Chaque bloc se valide contre le schéma JSON de son type (/schemas/blockchain/block.{type}.schema.json), qui refuse toute propriété additionnelle ; un bloc dont le JSON répète une clé est rejeté.

    Ce que cela prouve : Tous les vérificateurs lisent le même contenu : les analyseurs divergeant sur une clé dupliquée, un tel bloc pourrait se lire comme deux jeux de bulletins différents sous la même empreinte et la même signature.

    Repose sur Blockchain

  6. 6

    Rejouer le chemin 1 sur la chaîne.

    Sur le contenu des blocs : chaque signature en anneau contre les clés de son anneau, chaque ring_digest recalculé à partir de ses public_keys, l'unicité des images de clé, les bornes par anneau et globale contre le registre d'émargement du bloc closure, puis le recompte à partir des règles du bloc configuration et des charges utiles des blocs votes.

    Ce que cela prouve : Les garanties du chemin 1, désormais sur un registre dont l'authenticité, l'ordre et la complétude sont établis.

    Repose sur Registre public Dépouillement & recompte

  7. 7

    Vérifier l'ancrage Bitcoin.

    En option, chaque preuve .ots contre son fichier de bloc, avec l'outillage OpenTimestamps standard (ots verify). L'engagement est le SHA-256 simple du fichier. Une preuve en attente ne porte encore que les engagements des calendriers ; une preuve complétée désigne un bloc Bitcoin.

    Ce que cela prouve : L'antériorité : le bloc existait, octet pour octet, au plus tard au bloc Bitcoin attesté, indépendamment des clés de la plateforme, qui ne peut pas antidater un bloc Bitcoin.

    Repose sur Blockchain

Vérification · shell
# le trousseau publié, clés actives et retirées
curl -s https://admin.stg.condorcet.vote/.well-known/blockchain-signing-key > signing-keys.pgp

# pour chaque bloc n : la signature OpenPGP v6 (Sequoia, car GnuPG ne lit pas le v6)
sq verify --signer-file signing-keys.pgp --signature-file {n}.json.sig {n}.json

# le chaînage : l'empreinte doit égaler le previous_hash du bloc n + 1
openssl dgst -sha3-512 {n}.json

# en option, l'ancrage Bitcoin
ots verify -f {n}.json {n}.json.ots
Limites

Ce que ces chemins ne prouvent pas.

Les deux chemins vérifient ce qui a été publié. Ils ne remplacent pas la confiance accordée à la plateforme pendant le vote.

  • Le chemin 1 prend le registre tel qu'il est servi. Il ne dit pas si ce registre est complet ni s'il a été réécrit : la page du registre n'est pas immuable. C'est le rôle du chemin 2.
  • Une signature n'est pas l'immuabilité. La plateforme détient sa clé et pourrait signer une chaîne réécrite cohérente. Ce qui empêche une réécriture de passer inaperçue : les copies conservées par quiconque récupère les blocs au fil de leur publication, et l'ancrage OpenTimestamps, car un bloc réécrit ne peut pas être ancré avant sa réécriture.
  • Un tiers de confiance au moment du vote. Aucun registre ne prouve que la plateforme n'a pas observé les votants pendant le scrutin. Le mode « apportez votre clé » réduit ce qu'il faut lui confier.
  • Une participation fabriquée pour un absent. La plateforme pourrait marquer comme votant un inscrit qui n'a pas voté, et voter à sa place dans les bornes publiées ; seul ce votant peut le détecter, en contrôlant sa ligne d'émargement.
  • Qui a signé dans un anneau. Par construction, la signature en anneau ne révèle pas lequel des membres a signé. Un votant peut en revanche prouver son propre vote : le protocole n'offre pas de résistance à la coercition.