Format de checksum

Bonjour !

@kimamila @vit @moul @tuxmain

Ce fil concerne le format d’affichage des clefs publiques dans les clients (et notamment la question du checksum).

La question a été un peu explorée dans le sujet clefs publiques commençant par « 1 ». Au moment où je lance ce sujet, ces deux clefs publiques (binaires identiques) sont considérées différentes par Duniter et donnent des checksums différentes :

12BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx:8pQ
2BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx:5vi

le « 1 » de tête correspond à la valeur 0. Il est affiché, ou non, suivant la lib base58 utilisée.

@elois vient de coder dans Duniter que la clef privée correspondant à ces deux pubkeys puisse débloquer la monnaie reçue sur ces deux comptes. Il nous suggère d’utiliser une même checksum pour les deux pubkeys.

On en a rapidement discuté avec @moul, et ce sujet n’est pas léger, vu qu’il s’agit d’interopérabilité entre les clients et potentiellement d’un changement dans les pratiques des utilisateurs. Je vois deux situations à gérer :

  • l’utilisateur utilise plusieurs clients. Il doit avoir, pour les mêmes identifiants, la même clef publique et le même checksum
  • l’utilisateur veut envoyer de la monnaie sur une clef pub dont il a le checksum. Le client doit interpréter correctement le checksum, et ne pas renvoyer une erreur pour un checksum valide qu’il ne saurait pas traiter.

Je vois plusieurs options :

  1. Ne rien changer : continuer à utiliser le format checksum tel que défini par @Tortue, et laisser les « 1 » de tête. Dans ce cas, on considère que le checksum sert uniquement à valider que la chaîne entrée est cohérente, et ne sert pas à identifier la clef publique. Problème : suivant les clients, l’utilisateur aura un « 1 » de tête, ou non, et un checksum différent.

  2. détecter les cas où la pubkey a un « 1 » de tête, l’enlever, puis utiliser le format de checksum pré-cité et afficher la pubkey sans le « 1 » de tête. On continue à baser le checksum sur la chaîne de caractères, mais 1/ on n’a plus les « 1 » de tête, donc les clefs pub sont identiques entre tous les clients, et 2/ les clefs pub entrées avec un « 1 » de tête seraient tout de même cohérentes, car validées par le format de checksum actuel.

  3. partir sur un format d’affichage de pubkey qui se base sur la représentation binaire de la pubkey et contient le checksum. Problème : la représentation base58 de la clef pub est entièrement transformée. @moul a proposé ceci :

> import base58
> moul_pubkey = "GfKERHnJTYzKhKUma5h1uWhetbA8yHKymhVH2raf2aCP"
> moul_pubkey_checksum = base58.b58encode_check(moul_pubkey)
> moul_pubkey_checksum
> b'3cuhfZK54A9QKvtGTsTEvaX81Xta6dPdjHFuhS2mWCcbCdFHsT91hKStGQqtBy7Lgr'
> base58.b58decode_check(moul_pubkey_checksum)
> b'GfKERHnJTYzKhKUma5h1uWhetbA8yHKymhVH2raf2aCP'
> base58.b58decode(moul_pubkey_checksum)
> b'GfKERHnJTYzKhKUma5h1uWhetbA8yHKymhVH2raf2aCP{h\xbb#'
  1. redéfinir un format de checksum à partir du binaire de la clef publique, de 4 caractères pour le différencier de celui de @Tortue, par exemple en prenant les 4 derniers caractères de base58.b58encode_check(pubkey). Les derniers pour éviter de retrouver des « leading 1 » non souhaités.

Je suis fermement opposé à l’option 3. Je considère que n’importe qui doit pouvoir auditer la blockchain et y retrouver sa clef publique (ou son adresse) telle qu’il la connaît.

Je suis favorable à l’option 2. Le temps que tous les clients l’adoptent, il y aurait quelques cas où un utilisateur pourrait voir son checksum différemment sur deux clients, mais ce serait assez mineur.


Comme souvent, je pose des questions à la limite de mon champs de compétence, donc n’hésitez pas à me dire si je dis des sottises :wink:

2 J'aimes

À partir de la clé publique avec somme de contrôle intégré, il est toujours possible d’accéder à la clé publique classique :

>>> import base58

>>> moul_pubkey = "GfKERHnJTYzKhKUma5h1uWhetbA8yHKymhVH2raf2aCP"
>>> moul_pubkey_checksum = base58.b58encode_check(moul_pubkey)

>>> moul_pubkey_checksum
b'3cuhfZK54A9QKvtGTsTEvaX81Xta6dPdjHFuhS2mWCcbCdFHsT91hKStGQqtBy7Lgr'

>>> moul_pubkey = base58.b58decode_check(moul_pubkey_checksum)
>>> moul_pubkey
b'GfKERHnJTYzKhKUma5h1uWhetbA8yHKymhVH2raf2aCP'
1 J'aime

À noter que j’ai toujours en tête que l’on passe un jour sous un format d’adressage compressé qui permette de payer à n’importe-quel script et qui aura son checksun intégré. On paiera alors une adresse qui pourra être indifféremment un script ou une pubkey. L’adresse fera 23 octets en binaire et sera donc représentée par 32 caractères en base58.

Il faut donc bien garder en tête que ce format de checksum pour clé publique est temporaire, pour 1 an ou 2 grands max :wink:

2 J'aimes

Je trouve incohérent et peu pratique d’avoir une checksum différente en fonction des « 1 », car la différence pour l’algo qui calcule la checksum est la taille de la clé publique (32 octets avec le « 1 », 31 sans). Cette différence serait plutôt un bug des implémentations à taille variable (comme en Python, où une clé publique n’est qu’une chaîne à taille dynamique).

En fait, ça reviendrait à dire qu’une clé publique peut faire moins de 32 octets, donc qu’elle n’est définie non seulement par sa valeur, mais aussi par sa longueur.

Edit: pour l’instant j’ai modifié natools.py afin qu’il ajoute des zéros à la clé publique binaire pour qu’elle fasse 32 octets. Par exemple, les clés /^1{1,44}$/ ont toujours la même checksum, 3ud.

2 J'aimes

Oui, je suis d’accord : de mon point de vue, c’ets un bug de newbie (pour Cesium je parle).
Je vais aussi devoir corriger cesium afin qu’il veille à convertir en 32 octets. Le checksum généré sera donc uniquement celui qui correspond au 32 octets.
Ensuite, je vais faire en sorte que la lecture d’un checksum sur une clef de 31 octet fonctionne, en fallback. Nous pourrons retirer ce fallback dans quelques mois/années, quand plus personne n’utilisera l’ancien format.

Pas compliqué à gérer, donc, je trouve. Juste un autre bug :slight_smile:

1 J'aime

Ah oui bonne idée, comme ça l’utilisateur sait quand même si sa clé est valide. Je vais ajouter cette tolérance dans natools, avec un avertissement disant que le format est déconseillé.

1 J'aime