Clefs publiques commençant par "1"

OK cool !

Bon. Du coup les gens qui ont une pubkey qui commence par 1 verront le checksum changer. Tant que c’est bien communiqué, ok.

Dans ce cas, ce sont toutes les checksum de toutes les clefs publiques qui changeraient d’un coup. Si on veut faire ça, faut peut-être pas trop tarder… Avant que tout le monde se soit habitué à sa checksum ?

Voici le type de somme de contrôle que j’ai trouvé dans le module base58.

Voir la fonction suivante :

base58.b58decode_check()

Avec comme description du dépôt :

Base58 and Base58Check implementation compatible with what is used by the bitcoin network.
1 Like

Si ça ne tenais qu’a moi tout les traitements seraient en binaire depuis le début… Oui bien entendu qu’il faudrait le faire correctement de suite, de mon coté je peut faire en sorte que les clés avec leading 1 soient consommable dès la prochaine version de Duniter :slight_smile:

Et l’on voit que le checksum est bien calculé à partir de la représentation binaire et non de la représentation base 58 : https://github.com/keis/base58/blob/master/base58/init.py#L150

Ça veut donc dire qu’une clé peut faire moins de 43 caractères, donc que tous les programmes utilisant {44,43} ont un problème ? Par exemple, la clé 1 serait valide ?

Comment la checksum pourrait changer si elle est calculée depuis la forme binaire ? Il faudrait enlever des octets 0x00 au début ?

Oui, je ne vois aucune justification théorique à ce que la représentation base 58 d’une clé publique Ed25519 ne puissent pas faire moins de 43 caractères.

Si l’espace des 2^256 clés publiques possible était équiprobable, ce serait le cas pour ure clé sur 3364. Mais la fonction de la courbe elliptique Ed25519 n’est pas bijective, (plusieurs seed peuvent donner le même couple de clés), et à tendance à avoir plus de points parmi les très grands nombres. La probabilité réelle d’avoir une clé publique de moins de 43 caractères est donc bien plus faible, mais ce n’est pas impossible.

Par exemple, la clé 1 serait valide ?

Tout dépend ce que l’on entend par “valide”. Si l’on entend par là : un point existant sur la forme “Edward” de la courbe Curve25519 alors non.
Mais si l’on entend : toute clé publique qui peut être parsée et utilisée dans les traitements métier sans les faire planter alors oui.
Dans la pratique, aucun traitement ne vérifie que la clé publique correspond bien à “un point de la représentation d’Edward de la courbe Curve25519”. On vérifie simplement si un triplet (message, pubkey, signature) est valide ou non, et cette vérification peut sans problème se faire avec la clé zéro (représentée “1” en base58), c’est d’ailleurs ce que je fais dans mes tests unitaires :stuck_out_tongue:

Elle ne pourrait pas justement, car la représentation binaire est de taille fixe :slight_smile:

5 Likes

Du coup je viens de m’amuser à créer un TU qui cherche une clé publique ed25519 de moins de 43 caractères, et j’en ai trouvée une en moins d’une seconde !

Le test est sur la branche gen-pubkey-42-len du dépôt dubp-rs-libs

La clé publique en question : 6gy5DmTfGKEF79qru957rPdiDGtGXnHP49ocE7KXNX
Et la clé privée associée : 3ZS3coLVeNDi5MpvGeTR8UvXXbK42Aj5nL7Qjq1B7EobFBghLy8fyWAa7rzhnN2rp8ur4byH74GMWXwqEhnvow2w
Obtenue avec la seed : 9cfdVoFGFEswB66Hp14vfvB21sNqrFtTvbVTDPFaTXVH

Pour générer votre propre clée publique de moins de 43 caractères :

git clone https://git.duniter.org/libs/dubp-rs-libs.git -b gen-pubkey-42-len
cd dubp-rs-libs
cargo test --release -p dup-crypto --lib -- keys::ed25519::tests::tmp_find_key_42 --exact --nocapture

On peut donc confirmer définitivement par l’expérience qu’une clé publique ed25519 valide peu bel et bien faire moins de 43 caractères dans sa représentation base 58 et que tous les programmes qui utilisent une regex en {44,43} ont bien un problème :stuck_out_tongue:

EDIT : J’ai également trouvé une clé publique ed25519 à 41 caractères en laissant chauffer le cpu 15 secondes :

pubkey_b58="uCBY5yuaA83d1sqKZGz8cJLv79b53ftfND3cLupZH"
seed=DvVZM6C2VYnn88AUxjm9H4tWk9coJJPE7y65e8xxgvRd
expanded_base58_secret_key="4qeTGnRLyb2AtkjoZfZYLH9UY7dLk6kNvMHv3bmAfC46MuJJRGSw9GwurvLZ96w1QouWWpM1cRQVCYGhb8ddAe3D"

J’ai essayé avec 40 caractères, mais je n’ai rien après 60 secondes et j’ai pas envie de faire trop chauffer mon cpu donc j’ai arreté là :sweat_smile:

5 Likes

Si la limite basse est potentiellement inconnue, peut-on garder la règle de la limite haute à 44 caractères pour vérifier une clef base58 ?

Ça a l’air :

>>> len(base58.b58encode(b"\xff"*32))
44

Par contre, le module Python base58 a parfois un comportement bizarre :

>>> len(base58.b58decode("1"*44))
44
>>> len(base58.b58decode("1"+"a"*43))
33
>>> base58.b58decode("1"+"a"*43)
b'\x00\x08\x9a"p\xf8\xb8p\xbd_\x13#\x11\x17}\xbe\xc9\xadra\x84d\t\x06OU\xc2uyC^P\xd7'

Il ne faut donc pas oublier de virer les zéros en trop au début.

Et certaines clés base58 ne sont pas valides et font 33 octets, car 58^44 > 255^32.

2 Likes

Oui car toute clé publique ed25519 fait 32 octets et comme 58^44 > 2^256 on est certain que toutes les clés publiques ed25519 peuvent être représentées en base58 par 44 caractères ou moins :slight_smile:

Voilà qui est fait sur la branche oxyde-parse-and-verify-tx :smiley:

Et voici le test qui prouve qu’en DUBPv13 il sera possible de consommer les sources de la clé 1A avec la clé A :

https://git.duniter.org/nodes/typescript/duniter/-/blob/oxyde-parse-and-verify-tx/test/integration/transactions/transaction-unlock-pubkey-with-leading-1.ts

Cela nécessite un changement de protocole, car on change les conditions d’utilisation d’une source, il faudrait d’ailleurs que je le précise dans la RFC !

A noté que ma priorité étant désormais la migration de Duniter, lorsque je dois modifier un traitement dans Duniter j’en profite pour le migrer en même temps (dans la mesure du possible).
C’est ce que j’ai fait ici : j’ai migré en Rust le traitement qui vérifie que les preuves de déblocage d’une source sont valides (ce qui m’a demandé de migrer également le parser du script de conditions).

@matograine tu peux donc de suite générer la même checksum avec ou sans leading 1, le mieux est de le faire sur la représentation binaire comme le fait le module python base58 :slight_smile:

À noter que les comptes A et 1A seront toujours présentés comme différents via l’api BMA (car stockés en DB comme 2 comptes différents). Cela sera réglé lors de la migration de la DB, mais comme c’est un chantier titanesque ce sera probablement pour une future version (afin de ne pas bloquer la sortie de Duniter 1.9).

3 Likes

Fait : Dubp v13 (!1) · Merge requests · documents / RFCs · GitLab

3 Likes

Zut, il va falloir revoir le DUBP :sweat_smile:

A public key is to be understood as an Ed25519 public key.
Its format is a Base58 string of 43 or 44 characters, such as the following: …

C’est @moul qui a pointé ça, Duniter renvoie une erreur quand on lui fait des requêtes qui concernent des clefs publiques “courtes”.

2 Likes

Je descends à 40 pour DUBPv13. Je ne le sens pas de descendre en dessous car Duniter est faiblement typé (quasiment tous les champs sont des string), et donc ça peut causer des effets de bord chelous (comme considérer un champ comme une clé publique alors que c’est tout autre chose).

Quand la migration sera suffisamment avancée, les regex pubkey n’existeront plus car tout sera géré par le typage fort, la limite basse sera alors zéro au lieu de 40, mais ce ne sera pas avant 1 an voir plus.

2 Likes

Un message a été scindé en un nouveau sujet : Quelle priorité dans les devs Duniter?

Attention au biais de discussion : ce n’est pas parce que l’on parle d’un sujet que c’est sur ce sujet que je consacre le plus de temps, bien au contraire.

La majeure partie du temps que je consacre à Duniter ces dernières semaines n’a rien à voir avec ce sujet « Clefs publiques commençant par “1”»

2 Likes

Petite question : si tu modifie le protocole, il y a bien un risque de fork, non ?
Par exemple, sur mes noeuds, je suis repassée en v1.7 car impossible de finir une synchro en 1.8.
Si tu passes en prod cette modif, il suffira de consommer une clef plus courte pour déclencher un fork, non ?
Je me retrouverai alors avec des noeuds bloqués…

Voilà ce dont il est question, en terme de priorité…

Le changement de protocole ce fait automatiquement quand plus de 70% des nœuds du réseau son prêt. À ce moment-là, tous les nœuds sous ancienne version se désynchronise.

Même si je revert le support des clés courtes, quand le réseau sera en DUBPv13, Duniter 1.7 ne sera plus utilisable de toute façon. Tout changement de protocole est nécessairement cassant ne serait-ce par l’incrément du numéro de version du block.
De plus, DUBPv13 contient d’autres changements cassant, comme le changement de la définition de CSV pour devenir compatible avec les LN, ainsi que le retrait de la contrainte sur le blockstamp des docs transaction que tu me demandes de re prioriser.

Duniter 1.8 à passé une très longue campagne de test, les problèmes de sync ne sont pas liées au changement de version mais à l’inefficience du process de sync qui réalise beaucoup trop d’I/O, qui se ressent de plus en plus avec le nombre de blocs qui augmentent.

Le problème c’est que pour régler cela je ne vois pas d’autre moyen que de réécrire entièrement le process de synchronisation, ce qui demande au préalable de migrer toute la base de données leveldb, chantier titanesque sur lequel j’étais avant que tu ne me pousses a re prioriser GVA.

Mais ce n’est pas tout, la partie «network» de la sync pose aussi des problèmes, mais là il faut carrément créer une nouvelle couche réseau, c’est dans ma roadmap moyen/long terme.

En attendant, il est nécessaire de disposer d’un SSD pour synchroniser la blockchain, ou alors de copier le dossier data, je veux bien fournir une copie de mon dossier data si ça peut te débloquer :slight_smile:

1 Like

En fait il y a une autre solution pour les utilisateurs sur HDD: sync dans /dev/shm :

duniter --home /dev/shm/duniter sync g1.duniter.org
cp -r /dev/shm/duniter/duniter_default/data ~/.config/duniter/duniter_default/data
2 Likes

ok je comprends que, de toute façon, un changement de protocole aura lieu.

Quel est le checksum de la clef publique :

  • 11111111111111111111111pubKey49311
  • alias pubKey49311

Est-ce :

  • 14R ( issue de 11111111111111111111111pubKey49311 resultat avec 1 initaux)
  • 4Ru ( issue de 11111111111111111111111pubKey49311 resultat sans 1 initaux)
  • 12p ( issue de pubKey49311 resultat avec 1 initaux)
  • 2p7 ( issue de pubKey49311 resultat sans 1 initaux)

PS : actuellement, la fonction checkKey(‹ pubKey49311:??? ›) de g1lib.js considère les 4 comme valide.
En revanche pubKey2checksum(‹ pubKey49311 ›) comme pubKey2checksum(‹ 11111111111111111111111pubKey49311 ›) retournent 14R à moins de leur spécifier des paramètres optionnels pour obtenir les autres résultats.

3 Likes