Dans un précédent billet, nous avons étudié un peu le fonctionnement du protocole Bitcoin. Aujourd'hui, nous allons nous intéresser à une partie très spécifique de ce protocole : les adresses.

Rapide rappel. Pour recevoir des Bitcoins, il faut disposer d'une adresse Bitcoin, comme 1J3BnzUeHubrjdMuBjSPtpUy2wv7RchNyy. Pour dépenser les Bitcoins disponibles à cette adresse, il faut connaître la clé secrète associée (en l'occurrence, 5Jd4kDBTJnDmQwLv94gjWheWwsrvmRMGfLj438BBLdRtw4axSAy).

D'où diable sortent ces chaînes de caractères plutôt abstraites ? C'est ce que nous allons voir.

Un nom prédestiné

Clés privées, clés publiques

Si vous connaissez le concept de cryptographie asymétrique, vous allez voir que c'est très simple. En cryptographie asymétrique, on utilise un algorithme (RSA, DSA, ECDSA, etc.) pour générer une clé privée et une clé publique. Et bien, une adresse Bitcoin, c'est juste un clé publique, et la clé associée, c'est bien évidemment la clé privée. Ensuite, on va simplement présenter ces données sous une forme destinée à les rendre plus lisibles.

Bitcoin utilise l'algorithme ECDSA qui fait appel aux courbes elliptiques. La courbe Secp256k1, si on veut être précis. Vous pouvez vous renseigner sur le sujet si vous voulez savoir d'où sortent les nombres qui vont suivre, mais si ça vous gave vous pouvez vous contenter de me faire confiance (ayez confiaaaaaaaanceeeee…).

En pratique, on commence par générer une clé privée. À partir de cette clé privée, on génère la clé publique. L'opération inverse est bien évidemment impossible d'un point de vue pratique.

Générer une clé privée

Avec la version de l'algo ECDSA utilisée par Bitcoin, une clé privée est simplement un nombre entier compris entre 1 et 115792089237316195423570985008687907852837564279074904382605163141518161494337.

Point d'opération mathématique complexe, donc, juste générer un nombre aléatoire (ce qui est en fait plus difficile qu'il n'y parait, mais passons).

>>>> import random

>>>> N = 115792089237316195423570985008687907852837564279074904382605163141518161494337
>>>> privkey = random.randint(1, N - 1)
>>>> print privkey
48043200524453242678675397444692662200364073159048590385133969188377493477552L

Obtenir la clé publique

Pour obtenir l'adresse Bitcoin, on génère une clé publique à partir de la clé privée précédemment obtenue. J'ai déjà expliqué comment on passait de l'un à l'autre, et comme c'est un poil rébarbatif, je ne vais pas me répéter.

Il faut simplement rappeler qu'avec ECDSA, une clé publique est en fait un couple de deux entiers (x, y). Pour en simplifier la manipulation, on va juste représenter chaque nombre sur 32 octets, les concaténer, et préfixer tout ça par la valeur magique 0x04.

def priv_to_pub(privkey):
    """Get the associated public key."""
    nG = secp256k1_multiply(privkey)

    pubkey = b''.join([
        b'\x04',
        int_to_bytes(nG[0]).rjust(32, b'\x00'),
        int_to_bytes(nG[1]).rjust(32, b'\x00')
    ])

    return pubkey

Des données qui ne font pas saigner les yeux

Manipuler des nombre d'une centaine de chiffres ou des blobs binaires n'est pas très plaisant. C'est pour ça que Bitcoin propose un encodage spécial pour représenter les différentes valeurs.

Vous connaissez la base 10, qui consiste à utiliser les caractères « 0 » à « 9 » pour représenter un nombre. Et bien Bitcoin définit la base 58, qui utilise les chiffres et les lettres — majuscules et minuscules — sauf les caractères pouvant prêter à confusion : « 0 », « O », « I », « l ».

Bitcoin définit par ailleurs l'encodage B58Check, qui contient en plus une somme de contrôle.

Tout ça n'a pas très grand intérêt. Je vous met un lien vers un peu de code si ça vous branche mais au fond on s'en fout un peu, c'est juste un changement de représentation.

Si j'applique cet encodage, j'obtiens quelque chose qui ressemble un peu plus à ce qu'on a pu voir au départ.

>>>> privkey = 48043200524453242678675397444692662200364073159048590385133969188377493477552L
>>>> magic_prefix = b'\x80'
>>>> privkey_bytes = int_to_bytes(privkey)
>>>> privkey_encoded = b58c_encode(privkey_bytes, magic_prefix)
>>>> print privkey_encoded
5Jd4kDBTJnDmQwLv94gjWheWwsrvmRMGfLj438BBLdRtw4axSAy

Et enfin, l'adresse

J'ai menti. Je sais, c'est mal. Mais une adresse Bitcoin n'est pas une clé publique. Du moins, pas directement.

Pour passer de la clé publique à l'adresse, il faut simplement réaliser un double hashage (SHA-256 puis RIPEMD-160) avant d'encoder le résultat en Base58Check. Rien de bien sorcier, donc, mais notez qu'à partir d'une adresse Bitcoin, il n'est pas possible de récupérer directement la clé publique.

Jouer avec les adresses

Hors sujet

ATTENTION ! DANGER ! Les paragraphes qui vont suivres peuvent vous amener à prendre des risques de sécurité si vous ne comprenez pas bien ce que vous faites. Dans le doute, abstenez-vous.

Il existe un moyen assez simple de générer des adresses à la volée. En effet, une adresse est un nombre compris entre 1 et N ou N est grosso-modo égal à 2256. Quel algorithme pourrait on bien utiliser pour générer des nombres binaires à 256 chiffres ? SHA 256 bien sûr !

Le processus est simple : prenez une suite de mots, ou un fichier, ou n'importe quoi, et générez un hash grâce à l'algorithme sha256. Vous êtes a peu près certain d'obtenir une clé privée valide.

$ echo "Je suis ton père" | sha256sum
c39dbc05ed11880fe6fe6de5cc89bb02d73df712c8e31c007825e146a48d6829

Par conséquent, il est assez facile d'utiliser des passphrases pour générer des adresses aisément mémorisables.

Par exemple, un hash d'un célèbre proverbe produit l'adresse 1MrpUuKPumwmnF4NmfKyeY74vXbR19wJ9L. Il y a actuellement 0.1mBTC sur cette adresse, si vous trouvez le bon proverbe, vous gagnez le droit de les récupérer.

Attention toutefois car vous pourriez bien vous tirer une balle dans le portefeuille. En effet, la sécurité du Bitcoin repose sur le fait qu'il existe trop d'adresses différentes (2256) pour qu'une attaque bruteforce soit praticable. On dira que l'entropie d'une adresse (grosso-modo, la quantité d'information nécessaire pour l'exprimer) est 2256.

Si vous utilisez une suite de quelques mots, ou pire, une phrase connue, pour générer votre portefeuille, vous allez obtenir une entropie beaucoup moins importante.

Par exemple, la phrase « Je suis ton père » est composée de quatre mots. Imaginons un attaquant utilisant un logiciel qui teste toutes les adresses générées à partir de suites de mots, et utilisant un dictionnaire de 2500 mots. L'entropie de votre adresse sera de 25004, ce qui est très, très, très, très, très, très, très, très, très, très inférieur à 2256. Je peux vous assurer que vos Bitcoins ne resteront pas longtemps dans votre poche.

Même si vous mixez minuscule, majuscules, caractères bizarres et compagnie, vous serez encore très loin du compte.

Conclusion

Vous êtes désormais incollables sur les adresses Bitcoin. Je vous laisse, je vais acheter un paquet de chips.