nsi:tds:cryptographie:blockchain
Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
| nsi:tds:cryptographie:blockchain [2023/04/11 16:09] – goupillwiki | nsi:tds:cryptographie:blockchain [2023/05/08 01:14] (Version actuelle) – goupillwiki | ||
|---|---|---|---|
| Ligne 73: | Ligne 73: | ||
| </ | </ | ||
| - | === Bloc d' | + | === Blocs d' |
| Les blocs ordinaires recevront l' | Les blocs ordinaires recevront l' | ||
| Ligne 80: | Ligne 80: | ||
| <code python> | <code python> | ||
| - | (" | + | (" |
| </ | </ | ||
| - | === Information supplémentaire === | + | * Paul est la source (il donne de crédits) |
| + | * Judith est la cible (elle reçoit les crédits) | ||
| + | * 5 est la quantité de crédits échangés | ||
| + | * S est la signature permettant d' | ||
| + | |||
| + | Voir plus bas pour le fonctionnement de la signature. | ||
| Le bloc s' | Le bloc s' | ||
| Ligne 89: | Ligne 94: | ||
| * données (initialisation pour le bloc 0 et transaction pour les autres) | * données (initialisation pour le bloc 0 et transaction pour les autres) | ||
| - | Pour le hachage, on pourra utiliser | + | On utilise |
| <code python> | <code python> | ||
| Ligne 104: | Ligne 109: | ||
| <WRAP tip>On peut indiquer l' | <WRAP tip>On peut indiquer l' | ||
| + | |||
| + | === Signature === | ||
| + | |||
| + | Dans la transaction '' | ||
| + | |||
| + | Voyons comment la signature sera crée : | ||
| + | * Paul veut donner 5 unité à Judith. On crée le texte '' | ||
| + | * on encode le texte et on hache. On utilise pour cela '' | ||
| + | * on calcule la signature '' | ||
| + | * '' | ||
| + | * la transaction est alors complétée : '' | ||
| + | |||
| + | Dans l' | ||
| + | |||
| + | <code python> | ||
| + | ' | ||
| + | </ | ||
| + | |||
| + | Au moment de la vérification, | ||
| + | |||
| + | * comme dans ce qui précède, on produit le texte '' | ||
| + | * on hache ce texte : '' | ||
| + | * on cherche la version '' | ||
| + | * on déchiffre '' | ||
| + | * on compare si '' | ||
| === Sauvegarde === | === Sauvegarde === | ||
| - | Il peut être intéressant de sauvegarder un bloc sous forme d'un fichier. | + | Chaque |
| - | On pourra par exemple sauvegarder un bloc sous cette forme : | + | |
| + | Le fichier aura pour nom l' | ||
| + | |||
| + | Dans le cas du bloc initial, le bloc contiendra simplement les données. Par exemple | ||
| <code lang-none> | <code lang-none> | ||
| - | empreinte du bloc précédent en format hexdigest | + | Paul; |
| - | chaque ligne de donnée avec séparateur | + | Judith;92; |
| - | empreinte du bloc en format hexdigest | + | Michel; |
| + | Laure; | ||
| </ | </ | ||
| - | Il faudrait | + | Dans le cas d'un bloc d' |
| + | |||
| + | Le fichier contient | ||
| + | nom de la source;nom de la cible;str de value;hex de S | ||
| + | |||
| + | === chargement === | ||
| + | |||
| + | Si je sais que le dernier | ||
| + | * nom de la source | ||
| + | * nom de la cible | ||
| + | * value que l'on peut convertir en int | ||
| + | * signature qui est sous forme hex et que l'on peut passer en '' | ||
| ==== Chaîne ==== | ==== Chaîne ==== | ||
| Ligne 122: | Ligne 167: | ||
| Créons une classe '' | Créons une classe '' | ||
| - | Un objet '' | + | * L'objet '' |
| + | * chaque fois que la blockchain charge | ||
| - | La classe '' | + | Le bloc initial indique le compte initial |
| - | * ajouter un bloc : on donne une transaction, | + | |
| - | * lire l' | + | |
| - | ==== Signature ==== | + | Ainsi, si Paul commence à 45, Judith à 92 et que Paul donne 5 à Judith, alors Paul aura 40 et Judith 97. |
| - | Dans la transaction | + | On peut garder l' |
| - | Quand l' | + | <code python> |
| - | * calculer '' | + | comptes |
| - | * chiffrer '' | + | " |
| - | * fournir '' | + | " |
| + | " | ||
| + | " | ||
| + | } | ||
| + | </ | ||
| - | <WRAP box> | + | La blockchain, au gré des transactions, met à jour les valeurs des différents comptes. |
| - | * on fabrique le texte '' | + | |
| - | * on fait l' | + | Il pourra être utile aussi de créer, à la lecture |
| - | * on calcule l' | + | |
| - | * on obtient | + | |
| - | * reste à chiffrer avec Kpr de Paul : '' | + | |
| - | On obtiendra ici : | ||
| <code python> | <code python> | ||
| - | (" | + | keys = { |
| + | | ||
| + | | ||
| + | " | ||
| + | " | ||
| + | } | ||
| </ | </ | ||
| - | </ | ||
| - | Pour vérifier la signature, on doit : | + | === ajout de transaction === |
| - | * calculer '' | + | |
| - | * déchiffrer '' | + | |
| - | * vérifier que '' | + | |
| - | La signature permet de s'assurer que l'émetteur de la demande est bien le propriétaire de la clé privée liée à Kpu. Puisque la chaîne connaît les Kpu de tous les utilisateurs, | + | La classe |
| - | <WRAP tip>On aimerait ajouter une méthode dans '' | + | Une transaction est composée |
| - | ==== Vérification | + | la blockchain doit : |
| + | * vérifier que les identifiants existent, | ||
| + | * vérifier la signature, | ||
| + | * vérifier que la source dispose | ||
| - | Lors de l'ajout d'un bloc, il va falloir prévoir une étape de vérification. Pour chaque | + | On convient que la fonction renvoie |
| - | * vérifier que la signature, | + | |
| - | * vérifier que la demande est valide compte-tenu des comptes en l' | + | |
| - | ==== Sauvegarde ==== | + | * mise à jour des comptes, |
| + | * création du bloc correspondant, | ||
| + | * ajout du bloc à la suite des autres, | ||
| + | * sauvegarde du bloc | ||
| - | Il serait intéressant de prévoir | + | et dans ce cas la fonction renvoie |
| - | Il faudrait alors prévoir de recréer la chaîne à partir de cette sauvegarde. | + | ===== Proposition d' |
| + | Il faut utiliser, comme déjà dit, {{ : | ||
| + | |||
| + | <code python> | ||
| + | # blockchain.py | ||
| + | import hashlib | ||
| + | import os | ||
| + | import rsa | ||
| + | |||
| + | class Block: | ||
| + | def __init__(self, | ||
| + | """ | ||
| + | empreinte_precedent: | ||
| + | data: tableau donnant la liste des données à prendre en compte | ||
| + | """ | ||
| + | self.data = data | ||
| + | self.empreinte_precedent = empreinte_precedent | ||
| + | | ||
| + | def empreinte(self) -> str: | ||
| + | """ | ||
| + | renvoie l' | ||
| + | """ | ||
| + | # mettre empreinte_precedent, | ||
| + | # suivi de la version texte de data (__str__ ci dessous) | ||
| + | # encoder en utf8 pour obtenir un bytes b | ||
| + | # faire le hash avec hashlib.sha256(b) | ||
| + | # renvoyer le hexdigest du hash obtenu | ||
| + | | ||
| + | def __str__(self) -> str: | ||
| + | """ | ||
| + | renvoie une version texte de data | ||
| + | """ | ||
| + | # pas besoin d' | ||
| + | | ||
| + | def save(self): | ||
| + | """ | ||
| + | sauvegarde le bloc dans un fichier dont le nom est l' | ||
| + | du bloc précédent suivit de l' | ||
| + | """ | ||
| + | # le fichier doit contenir le contenu de __str__ | ||
| + | # si le fichier existe déjà, il ne faut rien faire | ||
| + | | ||
| + | def next_filename(self) -> str: | ||
| + | """ | ||
| + | renvoie le nom de fichier du bloc suivant | ||
| + | """ | ||
| + | return self.FOLDER + self.empreinte() + self.EXT | ||
| + | |||
| + | |||
| + | class BlockChain: | ||
| + | def __init__(self): | ||
| + | """ | ||
| + | lance la procédure de chargement pour construire la blockchain | ||
| + | """ | ||
| + | self.blocs = [] | ||
| + | self.keys = {} | ||
| + | self.credits = {} | ||
| + | self.load() | ||
| + | |||
| + | def load(self): | ||
| + | """ | ||
| + | charge la blockchain selon les fichiers | ||
| + | """ | ||
| + | # créer une liste self.blocs vide | ||
| + | # cherche le fichier 0.bloc qui est l' | ||
| + | # ce fichier contient : | ||
| + | # 0 | ||
| + | # les infos des comptes sous la forme : identifiant: | ||
| + | # | ||
| + | # créer le bloc0 avec les infos du fichier mettre bloc0 dans self.blocs | ||
| + | # créer un self.keys = { identifiant: | ||
| + | # créer un self.credits = { identifiant: | ||
| + | # à partir de là, tant que l' | ||
| + | # charger le fichier, lire la transaction, | ||
| + | | ||
| + | # pour info, on peut obtenir les noms de fichiers en faisant : | ||
| + | # fichiers = [f for f in os.listdir(' | ||
| + | | ||
| + | def add_transaction(id_source: | ||
| + | """ | ||
| + | id_source: identifiant de la source de l' | ||
| + | id_cible: identifiant de la cible de l' | ||
| + | value: quantité à transférer de id_source à id_cible | ||
| + | s: signature pour authentifie la transaction | ||
| + | renvoie True si la transaction a réussi, False sinon | ||
| + | """ | ||
| + | # vérifie que source et cible existent bien | ||
| + | # vérifie la signature | ||
| + | # vérifie si le compte source a assez de crédits | ||
| + | # modifie l' | ||
| + | # crée un bloc pour la transaction | ||
| + | # en indiquant l' | ||
| + | # ajoute le bloc dans la liste des blocs | ||
| + | # sauvegarder le bloc | ||
| + | |||
| + | def empreinte_transaction(self, | ||
| + | """ | ||
| + | id_source: identifiant source | ||
| + | id_cible: identifiant cible | ||
| + | value: quantité | ||
| + | renvoie l' | ||
| + | """ | ||
| + | # fabrique le texte formé de la façon id_source; | ||
| + | # encode, hash | ||
| + | # renvoie digest | ||
| + | |||
| + | def credit(self, | ||
| + | """ | ||
| + | renvoie la valeur de crédit pour identifiant | ||
| + | """ | ||
| + | </ | ||
| + | |||
| + | Il faudra donc créer manuellement un bloc initial '' | ||
| + | <code lang-none> | ||
| + | Paul; | ||
| + | Judith; | ||
| + | Michel; | ||
| + | Laure; | ||
| + | </ | ||
| + | |||
| + | On a besoin de simuler un client agissant sur la blockchain (un des utilisateurs). Si par exemple Paul veut faire une transaction, | ||
| + | <code python> | ||
| + | # client.py | ||
| + | |||
| + | import hashlib | ||
| + | import rsa | ||
| + | |||
| + | class Client: | ||
| + | def __init__(self, | ||
| + | """ | ||
| + | identifiant: | ||
| + | Kpr: clé privée (n,d) | ||
| + | """ | ||
| + | self.identifiant = identifiant | ||
| + | self.Kpr = Kpr | ||
| + | | ||
| + | def transaction(self, | ||
| + | """ | ||
| + | renvoie la transaction signée | ||
| + | """ | ||
| + | # la transaction signée est formée ainsi : | ||
| + | # (id_source, id_cible, value, signature) | ||
| + | # pour le calcul de la signature, on reprend le principe | ||
| + | # rencontré dans BlockChain.empreinte_transaction : | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # le résultat est la signature | ||
| + | </ | ||
| + | |||
| + | On pourra par montrer le fonctionnement de la façon suivante : | ||
| + | |||
| + | < | ||
| + | # demo.py | ||
| + | |||
| + | from blockchain import BlockChain | ||
| + | from client import Client | ||
| + | |||
| + | b = BlockChain() # charge le fichier 0.bloc | ||
| + | paul = Client(" | ||
| + | judith = Client(" | ||
| + | |||
| + | print(f" | ||
| + | print(f" | ||
| + | t = paul.transaction(" | ||
| + | success = b.add_transaction(*t) # * pour ventiler les morceaux du tuple t dans les arguments | ||
| + | |||
| + | if success: | ||
| + | print(" | ||
| + | # la transaction a été enregistrée et sera donc pris en compte | ||
| + | # à la prochaine exécution du script | ||
| + | else: | ||
| + | print(" | ||
| + | </ | ||
| + | | ||
| + | | ||
nsi/tds/cryptographie/blockchain.1681222146.txt.gz · Dernière modification : de goupillwiki
