Objectifs :
– Comprendre le concept de blockchain
– Découvrir le hachage et son rôle dans la sécurisation
– Implémenter une blockchain simple en Python
– Comprendre la notion de consensus et d’immutabilité
1. Qu’est-ce qu’une blockchain ?
Une blockchain est une base de données distribuée qui stocke des informations sous forme de blocs liés les uns aux autres de manière sécurisée et horodatée.
Concrètement, comment cela fonctionne ?
Chaque nouveau bloc contient l’empreinte numérique (le hash) du bloc précédent, créant ainsi une chaîne ininterrompue. Cette structure fait que modifier une information ancienne obligerait à recalculer tous les blocs suivants, ce qui est rendu quasiment impossible par le mécanisme de preuve de travail. La blockchain fonctionne sans autorité centrale : ce sont les utilisateurs du réseau, répartis dans le monde entier, qui valident collectivement chaque ajout grâce à un mécanisme de consensus. Une fois qu’une transaction est enregistrée et confirmée, elle devient inaltérable et visible par tous, garantissant transparence et confiance sans avoir besoin d’un tiers de confiance. C’est cette combinaison unique de décentralisation, de transparence et d’immutabilité qui fait la force de la technologie blockchain, bien au-delà des simples cryptomonnaies.
Explication d’une base de données distribuée appliquée à la blockchain
Prenons une analogie simple pour comprendre la différence entre une base de données classique et une base de données distribuée.
Analogue du cahier de textes de la classe
Base de données classique (centralisée) :
– C’est comme un cahier de textes de la classe que seul le professeur peut modifier
– Si le professeur perd le cahier ou le modifie, on perd les informations antérieures
– Les élèves doivent faire confiance au professeur
Base de données distribuée (blockchain) :
– C’est comme si chaque élève avait une copie identique du cahier
– Quand un élève ou le professeur propose d’ajouter une information, tout le monde doit être d’accord avant de l’écrire dans son propre cahier
– Si quelqu’un essaie de modifier son cahier, les autres verront que le sien est différent des leurs
Comparaison détaillée
| Aspect | Base de données classique | Base de données distribuée |
| Où sont stockées les données ? |
Sur un serveur central |
Sur des milliers d’ordinateurs (nœuds) dans le monde |
| Qui contrôle ? |
Une seule entité (entreprise, admin) |
Personne en particulier (tous les participants) |
| Qui peut modifier ? |
Un administrateur peut modifier |
Nécessite l’accord de la majorité |
| Et en cas de panne ? |
Si le serveur tombe, tout s’arrête |
Si un ordinateur tombe, les autres continuent |
| Confiance |
Doit faire confiance au centralisateur |
Pas besoin de confiance (mathématiques) |
Exemple concret : Un registre de transactions
Système bancaire classique (centralisé) :
Banque Centrale (serveur unique)
└── Compte Alice: 1000€
└── Compte Bob: 500€
└── Compte Charlie: 200€
Si Alice donne 50€ à Bob :
Alice envoie la demande à la banque
La banque modifie son registre unique
Tout le monde doit faire confiance à la banque
Blockchain (distribuée) :
Ordinateur d'Alice: Alice:1000€ | Bob:500€ | Charlie:200€
Ordinateur de Bob: Alice:1000€ | Bob:500€ | Charlie:200€
Ordinateur de Charlie: Alice:1000€ | Bob:500€ | Charlie:200€
Ordinateur de David: Alice:1000€ | Bob:500€ | Charlie:200€
(1000 autres ordinateurs...)
Si Alice donne 50€ à Bob :
1. Alice annonce à tous : "Je donne 50€ à Bob"
2. Chaque ordinateur vérifie qu'Alice a bien 50€
3. Si la majorité est d'accord, tous mettent à jour leur copie
4. Personne ne peut tricher car les autres ont la bonne version
Avantages pédagogiques pour comprendre
1. Pas de point de défaillance unique
– Si un ordinateur tombe en panne, des milliers d’autres ont la même info
– Si quelqu’un pirate un ordinateur, les autres détectent l’incohérence
2. Transparence totale
– Tout le monde peut voir toutes les transactions
– Mais on ne voit que les adresses (pseudonymes), pas les identités réelles
3. Consensus démocratique
– Pour ajouter un bloc, il faut que plus de 50% des « mineurs » soient d’accord
– C’est ce qu’on appelle le consensus
4. Impossibilité de tricher
– Pour modifier un ancien bloc, il faudrait modifier la copie de PLUS DE LA MOITIÉ des ordinateurs dans le monde
– C’est mathématiquement quasi impossible (coûterait des milliards d’euros)
Visualisation simple
# Simulation simple d'une base distribuée
class NoeudReseau:
def __init__(self, nom):
self.nom = nom
self.registre = {"Alice": 100, "Bob": 50}
def proposer_transaction(self, donneur, receveur, montant):
if self.registre[donneur] >= montant:
# Proposition de modification
return {"donneur": donneur, "receveur": receveur, "montant": montant}
return None
# Création du réseau distribué (plusieurs ordinateurs)
reseau = [
NoeudReseau("Ordi_Alice"),
NoeudReseau("Ordi_Bob"),
NoeudReseau("Ordi_Charlie"),
NoeudReseau("Ordi_David")
]
# Transaction proposée
transaction = reseau[0].proposer_transaction("Alice", "Bob", 30)
# Vote de chaque nœud
votes = 0
for noeud in reseau:
if noeud.registre["Alice"] >= 30:
votes += 1
print(f"{noeud.nom} vote OUI")
else:
print(f"{noeud.nom} vote NON")
# Consensus
if votes > len(reseau) / 2: # Majorité
print("✅ Consensus atteint ! Transaction validée")
# Tous les nœuds mettent à jour leur registre
for noeud in reseau:
noeud.registre["Alice"] -= 30
noeud.registre["Bob"] += 30
else:
print("❌ Pas de consensus - Transaction rejetée")
>>> Ordi_Alice vote OUI
Ordi_Bob vote OUI
Ordi_Charlie vote OUI
Ordi_David vote OUI
✅ Consensus atteint ! Transaction validée
En résumé
Base de données distribuée = des milliers d’ordinateurs qui ont tous la même information et qui doivent se mettre d’accord avant d’ajouter quoi que ce soit. C’est comme si toute la classe avait le même cahier de textes et vérifiait ensemble chaque nouvelle information avant de l’écrire.
Cette caractéristique rend la blockchain :
– Plus sécurisée (pas de point faible unique)
– Plus transparente (tout le monde voit tout)
– Plus démocratique (décisions collectives)
– Inaltérable (impossible de modifier sans que les autres ne s’en aperçoivent)
Caractéristiques principales :
– Décentralisation : Pas d’autorité centrale
– Transparence : Toutes les transactions sont visibles
– Immutabilité : Une fois enregistrées, les données ne peuvent plus être modifiées
– Sécurité : Utilisation de la cryptographie
Il est conseillé de faire fonctionner les scripts python pour une compréhension accrue de cet article, par exemple dans Basthon ou sur votre environnement habituel.
Pour un bon fonctionnement de ces scripts dans la suite de cet article vous devez importer les modules suivants :
# Import des bibliothèques nécessaires
import hashlib
import json
from datetime import datetime
import pandas as pd
from IPython.display import display, HTML
print("Bibliothèques importées avec succès !")
2. Le hachage : le cœur de la blockchain
Le hachage est une fonction mathématique qui transforme des données d’entrée en une chaîne de caractères de taille fixe.
Propriétés importantes :
1. Déterministe : Même entrée = même hash
2. Rapide à calculer
3. Impossible de remonter à l’entrée (sens unique)
4. La moindre modification change totalement le hash
Retrouvez mon article détaillé sur le SHA256 dans cette revue.
Qu’est-ce que SHA256 ?
SHA256 = Secure Hash Algorithm 256 bits
– « Secure » = sécurisé (résiste aux attaques)
– « Hash » = fonction de hachage
– « 256 » = produit toujours 256 bits (32 octets) en sortie
Pourquoi SHA256 dans la blockchain ?
1. Taille fixe garantie 📏
import hashlib
# Peu importe la taille d'entrée, SHA256 donne TOUJOURS 64 caractères hexadécimaux
textes = ["a", "NSI", "Un très long texte..." * 1000]
for texte in textes:
hash_resultat = hashlib.sha256(texte.encode()).hexdigest()
print(f"Entrée ({len(texte)} car.) → Hash SHA256 ({len(hash_resultat)} car.)")
print(f"'{texte[:42]}' → {hash_resultat}")
# Résultat : TOUJOURS 64 caractères hexadécimaux !
>>> Entrée (1 car.) → Hash SHA256 (64 car.)
'a' → ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb
Entrée (3 car.) → Hash SHA256 (64 car.)
'NSI' → a0c87b3a9a3f13c4dc2ce2abde4d7dd4a5fb2fd26af757ccfe22cf5ce4840ecf
Entrée (21000 car.) → Hash SHA256 (64 car.)
'Un très long texte...Un très long texte...' → 7b4af83cfbbb1f3089159a3144fbbe485d283fdfedbb4f9f0d2052a0a3ec16f4
2. Propriété d’avalanche ⛰️
# La moindre modification change TOUT le hash
message1 = "Alice donne 10€ à Bob"
message2 = "Alice donne 10€ à Bob." # Un point en plus !
hash1 = hashlib.sha256(message1.encode()).hexdigest()
hash2 = hashlib.sha256(message2.encode()).hexdigest()
print(f"Message 1: {message1}")
print(f"Hash 1: {hash1[:30]}...")
print(f"Message 2: {message2}")
print(f"Hash 2: {hash2[:30]}...")
if hash1 != hash2:
print("\n✅ Même avec 1 caractère de différence, les hash sont COMPLÈTEMENT différents !")
>>> Message 1: Alice donne 10€ à Bob
Hash 1: dcb9b3bc4a118c83965427433de6fe...
Message 2: Alice donne 10€ à Bob.
Hash 2: a8d58b572a33f4f4ca101533715145...
✅ Même avec 1 caractère de différence, les hash sont COMPLÈTEMENT différents !
3. Impossible à inverser 🔒
# SHA256 est à sens unique
def demonstration_sens_unique():
print("🔐 On peut calculer le hash, mais pas retrouver le message :")
message_secret = "MotDePasseSuperSecret"
hash_secret = hashlib.sha256(message_secret.encode()).hexdigest()
print(f"Message secret : {message_secret}")
print(f"Hash : {hash_secret[:30]}...")
print("\nSi quelqu'un pirate la blockchain et trouve ce hash :")
print("❌ Il ne peut PAS retrouver le message original !")
print("✅ Mais il peut vérifier si un message proposé correspond au hash")
>>> demonstration_sens_unique()
🔐 On peut calculer le hash, mais pas retrouver le message :
Message secret : MotDePasseSuperSecret
Hash : 72bb4dffe16f935aa619207c5c12fd...
-
Si quelqu'un pirate la blockchain et trouve ce hash :
❌ Il ne peut PAS retrouver le message original !
✅ Mais il peut vérifier si un message proposé correspond au hash
Pourquoi SHA256 et pas un autre ?
SHA256 a été choisi pour Bitcoin (et la plupart des blockchains) car :
| Propriété | Explication | Pourquoi c’est important |
| Sécurité prouvée |
Existe depuis 2001, jamais cassé |
On lui fait confiance |
| Rapidité |
Très rapide à calculer |
Les mineurs peuvent faire des milliards de calculs |
| Déterministe |
Même entrée = même sortie |
Tout le monde est d’accord sur le résultat |
| Résistance aux collisions |
Impossible de trouver 2 messages avec le même hash |
Personne ne peut créer de faux blocs |
Démonstration simple avec SHA256
def atelier_sha256():
# 1. Test avec différents types de données
print("1 SHA256 avec différents types :")
donnees_test = [
"42", # Un nombre
"42", # Le même nombre (vérification)
"43", # Nombre différent
"Hello World", # Texte
"" # Chaîne vide
]
for donnee in donnees_test:
hash_result = hashlib.sha256(str(donnee).encode()).hexdigest()
print(f"'{donnee}' → {hash_result[:20]}...")
# 2. Démonstration de la taille fixe
print(f"\n2 Taille fixe : Toujours 64 caractères hexadécimaux")
print(f" Un caractère → {len(hashlib.sha256(b'a').hexdigest())} caractères")
print(f" Un livre entier → {len(hashlib.sha256(b'a'*1000000).hexdigest())} caractères")
# 3. Propriété d'avalanche visuelle
print("\n3 Effet d'avalanche (visualisation) :")
msg_base = "NSI"
msg_modifie = "NSi" # juste 'i' minuscule au lieu de 'I' majuscule
hash_base = hashlib.sha256(msg_base.encode()).hexdigest()
hash_modifie = hashlib.sha256(msg_modifie.encode()).hexdigest()
print(f"'{msg_base}' → {hash_base}")
print(f"'{msg_modifie}' → {hash_modifie}")
# Comparaison caractère par caractère
differences = sum(1 for a, b in zip(hash_base, hash_modifie) if a != b)
print(f"\n👉 {differences} caractères différents sur 64 !")
atelier_sha256()
>>>🔨 Atelier SHA256
1 SHA256 avec différents types :
'42' → 73475cb40a568e8da8a0...
'42' → 73475cb40a568e8da8a0...
'43' → 44cb730c420480a0477b...
'Hello World' → a591a6d40bf420404a01...
'' → e3b0c44298fc1c149afb...
-
2 Taille fixe : Toujours 64 caractères hexadécimaux
Un caractère → 64 caractères
Un livre entier → 64 caractères
-
3 Effet d'avalanche (visualisation) :
'NSI' → a0c87b3a9a3f13c4dc2ce2abde4d7dd4a5fb2fd26af757c
cfe22cf5ce4840ecf
'NSi' → 5c308e3beb80e8f9559b3e0a08ba4bc6f7669dbca05353f
053d89335a4e96c4e
-
👉 61 caractères différents sur 64 !
Résumé
SHA256, c’est comme une machine à hot-dogs 🌭
– Tu mets n’importe quoi dedans (steak, salade, cornichon)
– La machine te rend TOUJOURS un hot-dog de la même taille
– Si tu changes ne serait-ce qu’un grain de sel, le hot-dog est COMPLÈTEMENT différent
– Impossible de retrouver les ingrédients à partir du hot-dog
Comparaison avec d’autres hash
def comparer_hashage(texte):
print(f"Texte à hasher : '{texte}'")
print(f"SHA256 : {hashlib.sha256(texte.encode()).hexdigest()[:40]}...")
print(f"SHA1 : {hashlib.sha1(texte.encode()).hexdigest()[:40]}...")
print(f"MD5 : {hashlib.md5(texte.encode()).hexdigest()[:40]}...")
print("-" * 50)
print("🔬 Comparaison des algorithmes de hash :")
comparer_hashage("NSI")
comparer_hashage("NSI c'est génial!")
print("✅ SHA256 est le plus sécurisé (utilisé par Bitcoin)")
print("⚠️ MD5 et SHA1 sont maintenant considérés comme vulnérables")
>>>🔬 Comparaison des algorithmes de hash :
Texte à hasher : 'NSI'
SHA256 : a0c87b3a9a3f13c4dc2ce2abde4d7dd4a5fb2fd2...
SHA1 : 5a63a58f8d68fd8d8dc685aafe89a626036d7619...
MD5 : 5848127ecd37d8c56f45572e9ed4cc6a...
--------------------------------------------------
Texte à hasher : 'NSI c'est génial!'
SHA256 : 35b2efe9fe83531ca6753f536607b5b0f8ad596a...
SHA1 : e0922b950f59af9671ce00c6161097276c9f52ae...
MD5 : 149c9273e2e27d570f9fac0f432a4f7f...
--------------------------------------------------
✅ SHA256 est le plus sécurisé (utilisé par Bitcoin)
⚠️ MD5 et SHA1 sont maintenant considérés comme vulnérables
Pourquoi retenir SHA256 ?
1. C’est le standard de l’industrie (Bitcoin, Ethereum, etc.)
2. Il garantit l’immuabilité de la blockchain
3. Il permet le minage (trouver un hash qui commence par N zéros)
4. Il sécurise les transactions sans révéler leur contenu
En résumé : SHA256 est le « super-héros » silencieux qui rend la blockchain fiable et sécurisée !
3. Création d’un bloc
Un bloc contient :
– Un index (position dans la chaîne)
– Un timestamp (horodatage)
– Des données (transactions)
– Le hash du bloc précédent (création du lien)
– Son propre hash (identifiant unique)
Définition simple
Timestamp = « Empreinte de temps » en français, ou plus simplement horodatage.
C’est comme une date et heure précises qu’on colle sur chaque bloc pour savoir EXACTEMENT quand il a été créé.
Analogies du quotidien
1. Le cachet de la poste ✉️
Quand tu envoies une lettre recommandée, la poste met un cachet avec la date. Ça prouve que ta lettre a été envoyée à un moment précis. Le timestamp dans la blockchain, c’est EXACTEMENT la même chose !
2. La photo avec la date 📸
Souviens-toi des appareils photo qui imprimaient la date en bas des photos. Le timestamp, c’est ça : une preuve que le bloc existait à ce moment-là.
3. L’horodatage sur une copie 📝
Quand tu rends un devoir sur Pronote, il y a marqué « rendu le 15/03/2024 à 14h32 ». Personne ne peut prétendre l’avoir rendu plus tôt !
Comment ça marche techniquement ?
from datetime import datetime
import time
# Exemple 1: Timestamp simple
moment_present = datetime.now()
print(f"Timestamp lisible : {moment_present}")
# Exemple 2: Timestamp en secondes (standard informatique)
timestamp_unix = time.time()
print(f"Timestamp Unix (secondes depuis 1970) : {timestamp_unix}")
>>>Timestamp lisible : 2026-03-23 12:52:28.965000
Timestamp Unix (secondes depuis 1970) : 1774288348.997
Pourquoi deux formats ?
– Format lisible : pour nous, humains
– Format secondes : pour les ordinateurs (plus facile à comparer)
Pourquoi c’est CRUCIAL dans une blockchain ?
1. Prouver l’ordre des événements 📅
# Sans timestamp, on ne saurait pas dans quel ordre sont les blocs !
bloc_1 = {"index": 1, "transaction": "Alice donne 10€ à Bob"}
bloc_2 = {"index": 2, "transaction": "Bob dépense ses 10€"}
# Mais si quelqu'un inverse l'ordre, Bob dépense de l'argent qu'il n'a pas encore !
# Le timestamp empêche ça :
bloc_1_avec_timestamp = {
"index": 1,
"transaction": "Alice donne 10€ à Bob",
"timestamp": "2024-12-15 10:00:00" # D'abord Alice donne
}
bloc_2_avec_timestamp = {
"index": 2,
"transaction": "Bob achète un café",
"timestamp": "2024-12-15 10:05:00" # Ensuite Bob dépense
}
# L'ordre est clair et vérifiable !
2. Éviter la double dépense 💰
# Situation problématique sans timestamp
print("🚨 SANS TIMESTAMP :")
transaction_1 = "Bob donne 10€ à Alice"
transaction_2 = "Bob donne 10€ à Charlie"
# On ne sait pas laquelle est valide ! Bob a peut-être dépensé 2 fois les mêmes 10€
# Avec timestamp, c'est clair
print("\n✅ AVEC TIMESTAMP :")
transaction_1 = {"montant": "10€", "de": "Bob", "à": "Alice", "timestamp": "10:00"}
transaction_2 = {"montant": "10€", "de": "Bob", "à": "Charlie", "timestamp": "10:01"}
if transaction_2["timestamp"] > transaction_1["timestamp"]:
print("Bob a dépensé ses 10€ à 10:00, puis à 10:01 il n'avait plus rien → TRANSACTION FRAUDULEUSE DÉTECTÉE !")
3. Le timestamp dans le hachage 🔗
import hashlib
import json
from datetime import datetime
def creer_bloc(transaction):
bloc = {
"transaction": transaction,
"timestamp": str(datetime.now()), # Le timestamp est inclus !
"previous_hash": "abc123..."
}
# Le hash est calculé à partir de TOUT le bloc, y compris le timestamp
bloc_string = json.dumps(bloc, sort_keys=True)
bloc["hash"] = hashlib.sha256(bloc_string.encode()).hexdigest()
return bloc
# Si on essaye de modifier le timestamp après coup :
bloc = creer_bloc("Alice → Bob: 10€")
print(f"Hash original: {bloc['hash'][:20]}...")
# On modifie même juste 1 seconde
bloc["timestamp"] = "2024-12-16" # Changement de jour
nouveau_hash = hashlib.sha256(json.dumps(bloc, sort_keys=True).encode()).hexdigest()
print(f"Nouveau hash: {nouveau_hash[:20]}...")
print("👀 Le hash a complètement changé ! La blockchain détecte la modification.")
Jeu pédagogique : « Détective du temps »
import random
from datetime import datetime, timedelta
print(" JEU : DÉTECTIVE DU TIMESTAMP")
print("Voici 3 transactions. Laquelle est frauduleuse ?\n")
transactions = [
{
"description": "Alice achète un café",
"timestamp": datetime.now()
},
{
"description": "Alice achète un sandwich",
"timestamp": datetime.now() - timedelta(hours=1)
},
{
"description": "Alice donne 50€ à Bob",
"timestamp": datetime.now() + timedelta(days=1) # Dans le futur !
}
]
for i, t in enumerate(transactions, 1):
print(f"{i}. {t['description']} - {t['timestamp'].strftime('%d/%m/%Y %H:%M')}")
print("\n🔍 Indice : Regarde bien les dates...")
print("✅ Réponse : La transaction 3 est frauduleuse car elle a un timestamp DANS LE FUTUR !")
print("Dans une vraie blockchain, impossible d'avoir un bloc avec une date future.")
>>> JEU : DÉTECTIVE DU TIMESTAMP
Voici 3 transactions. Laquelle est frauduleuse ?
-
1. Alice achète un café - 23/03/2026 12:58
2. Alice achète un sandwich - 23/03/2026 11:58
3. Alice donne 50€ à Bob - 24/03/2026 12:58
-
🔍 Indice : Regarde bien les dates...
✅ Réponse : La transaction 3 est frauduleuse car elle a
un timestamp DANS LE FUTUR !
Dans une vraie blockchain, impossible d'avoir un bloc a
vec une date future.
Récapitulatif
| Propriété | Explication | Analogue |
| Horodatage |
Date/heure exacte de création |
Cachet de la poste |
| Précision |
Jusqu’à la milliseconde |
Chronomètre de compétition |
| Inaltérable |
Inclus dans le hash |
Si tu grattes la date sur un ticket, il n’est plus valable |
| Ordre |
Sait quel bloc vient avant quel autre |
Photos datées dans un album |
Points clés à retenir
1. Le timestamp est comme une signature temporelle - il dit « ce bloc existait à ce moment précis »
2. Il est dans le hash - si quelqu’un essaie de le modifier, tout le bloc devient invalide
3. Il est universel - tous les ordinateurs du réseau utilisent la même référence temporelle
4. Il résout les conflits - si deux blocs sont proposés en même temps, celui avec le timestamp le plus ancien est prioritaire
5. Il est vérifié - impossible d’avoir un bloc avec une date future (ce serait détecté immédiatement)
Exercice
# À faire avec les élèves :
print("📝 EXERCICE : À toi de jouer !")
# Crée ton propre bloc avec timestamp
mon_bloc = {
"timestamp": datetime.now(),
"couleur_preferee": input("Quelle est ta couleur préférée ? ")
}
# Calcule son hash
hash_du_bloc = hashlib.sha256(str(mon_bloc).encode()).hexdigest()
print(f"\n✅ Ton bloc personnel a été créé à {mon_bloc['timestamp']}")
print(f"Il a pour identifiant unique (hash) : {hash_du_bloc[:30]}...")
# Maintenant, si tu changes ne serait-ce qu'une lettre dans le message :
print("\n🔄 Essaie de modifier ton message ou pas pour constater que tu obtiens un hash totalement différent ...")
print("👉 C'est ça, la magie de la blockchain !")
Le timestamp, c’est finalement assez simple : c’est juste la date de naissance du bloc ! Et comme pour nous, cette date fait partie de notre identité et ne peut pas être changée sans tout modifier.
4. Création de la blockchain
La blockchain est une liste chaînée de blocs. Le premier bloc est appelé bloc genesis. Voir ci-dessous l’implantation en Programmation Orientée Objet :
class Bloc:
def __init__(self, index, transactions, timestamp, hash_precedent):
self.index = index
self.transactions = transactions
self.timestamp = timestamp
self.hash_precedent = hash_precedent
self.nonce = 0 # Sera utilisé pour le minage
self.hash = self.calculer_hash()
def calculer_hash(self): #Calcule le hash du bloc
bloc_string = json.dumps({'index': self.index,'transactions': self.transactions,
'timestamp': str(self.timestamp),'hash_precedent': self.hash_precedent,
'nonce': self.nonce}, sort_keys=True)
return hashlib.sha256(bloc_string.encode()).hexdigest()
def afficher(self): #Affiche les informations du bloc
print(" Bloc :",self.index)
print(" Horodatage :",self.timestamp)
print(" Transactions :",self.transactions)
print(" Hash précédent :",self.hash_precedent[:20])
print(" Hash :",self.hash[:20])
print(" Nonce :",self.nonce)
print("-"*50)
class Blockchain:
def __init__(self):
self.chain = [self.creer_bloc_genesis()]
def creer_bloc_genesis(self):
"""Crée le premier bloc de la chaîne"""
return Bloc(0, ["Genesis Block"], datetime.now(), "0"*64)
def dernier_bloc(self):
"""Retourne le dernier bloc de la chaîne"""
return self.chain[-1]
def ajouter_bloc(self, transactions):
"""Ajoute un nouveau bloc à la chaîne"""
nouveau_bloc = Bloc(index=len(self.chain),transactions=transactions,timestamp=datetime.now(),
hash_precedent=self.dernier_bloc().hash)
self.chain.append(nouveau_bloc)
return nouveau_bloc
def verifier_integrite(self):
"""Vérifie si la blockchain est valide"""
for i in range(1, len(self.chain)):
bloc_actuel = self.chain[i]
bloc_precedent = self.chain[i-1]
if bloc_actuel.hash != bloc_actuel.calculer_hash(): # Vérification du hash du bloc actuel
return False, "Bloc "+str(i)+" : hash invalide"
if bloc_actuel.hash_precedent != bloc_precedent.hash: # Vérification du lien avec le bloc précédent
return False, "Bloc "+str(i)+" : lien rompu avec le bloc précédent"
return True, "✅ Blockchain valide !"
def afficher_chaine(self):
"""Affiche tous les blocs de la chaîne"""
for bloc in self.chain:
bloc.afficher()
5. Test de notre blockchain
# Création de la blockchain
ma_blockchain = Blockchain()
# Ajout de quelques blocs avec des transactions
print(" Création de la blockchain... ")
transactions_1 = ["Alice envoie 10 BTC à Bob", "Charlie envoie 5 BTC à David"]
bloc1 = ma_blockchain.ajouter_bloc(transactions_1)
transactions_2 = ["Bob envoie 3 BTC à Eve", "Frank envoie 2 BTC à Grace"]
bloc2 = ma_blockchain.ajouter_bloc(transactions_2)
transactions_3 = ["Alice envoie 1 BTC à Charlie", "David envoie 4 BTC à Bob"]
bloc3 = ma_blockchain.ajouter_bloc(transactions_3)
# Affichage de la blockchain complète
ma_blockchain.afficher_chaine()
# Vérification de l'intégrité
est_valide, message = ma_blockchain.verifier_integrite()
print(" Vérification :",message)
>>> Création de la blockchain...
Bloc : 0
Horodatage : 2026-03-22 12:27:08.808000
Transactions : ['Genesis Block']
Hash précédent : 00000000000000000000
Hash : dc85c22274ac015cf845
Nonce : 0
--------------------------------------------------
Bloc : 1
Horodatage : 2026-03-22 12:27:08.808000
Transactions : ['Alice envoie 10 BTC à Bob', 'Charlie envoie 5 BTC à David']
Hash précédent : dc85c22274ac015cf845
Hash : f755e99aa23ec4a0b043
Nonce : 0
--------------------------------------------------
Bloc : 2
Horodatage : 2026-03-22 12:27:08.808000
Transactions : ['Bob envoie 3 BTC à Eve', 'Frank envoie 2 BTC à Grace']
Hash précédent : f755e99aa23ec4a0b043
Hash : c807b707afcc6a5a4a6f
Nonce : 0
--------------------------------------------------
Bloc : 3
Horodatage : 2026-03-22 12:27:08.808000
Transactions : ['Alice envoie 1 BTC à Charlie', 'David envoie 4 BTC à Bob']
Hash précédent : c807b707afcc6a5a4a6f
Hash : f7bb0f9d57b4a48a94a9
Nonce : 0
--------------------------------------------------
Vérification : ✅ Blockchain valide !
6. Démonstration de l’immutabilité
Essayons de modifier une transaction dans un bloc existant pour voir ce qui se passe !
print("⚠️ Tentative de modification frauduleuse...")
# On modifie la première transaction du bloc 1
bloc_modifie = ma_blockchain.chain[1] # Bloc index 1 (deuxième bloc)
print("Avant modification :",bloc_modifie.transactions)
# Tentative de fraude
bloc_modifie.transactions = ["Alice envoie 1000 BTC à Bob (FRAUDE)", "Charlie envoie 5 BTC à David"]
print("Après modification :",bloc_modifie.transactions)
# Recalcul du hash après modification
nouveau_hash = bloc_modifie.calculer_hash()
print("Ancien hash :",bloc_modifie.hash[:30])
print("Nouveau hash :",nouveau_hash[:30])
# Vérification de l'intégrité,
print("🔍 Vérification après la modification :")
est_valide, message = ma_blockchain.verifier_integrite()
print(message)
>>> ⚠️ Tentative de modification frauduleuse...
Avant modification : ['Alice envoie 10 BTC à Bob', 'Cha
rlie envoie 5 BTC à David']
Après modification : ['Alice envoie 1000 BTC à Bob (FRA
UDE)', 'Charlie envoie 5 BTC à David']
Ancien hash : a582d7178730aeb4c1b814bdad4dee
Nouveau hash : b1c91bff46c68a53bfd74deecdee25
🔍 Vérification après la modification :
Bloc 1 : hash invalide
7. Le minage et la preuve de travail (Proof of Work)
Dans une vraie blockchain (comme Bitcoin), les blocs sont « minés ». Le minage consiste à trouver un hash qui commence par un certain nombre de zéros. C’est ce qui rend la modification de la blockchain extrêmement difficile !
⛏️ Qu’est-ce que le minage ?
Le minage, c’est comme une compétition de calcul mental où des ordinateurs du monde entier s’affrontent pour avoir le droit d’ajouter le prochain bloc à la blockchain.
🎯 La contrainte du « hash qui commence par des zéros »
Imagine qu’un professeur demande à toute la classe de trouver un nombre qui, quand on l’ajoute à une phrase, donne un résultat commençant par trois zéros. Tu ne peux pas calculer directement la solution : tu dois essayer des nombres un par un jusqu’à trouver le bon.
C’est exactement ce que font les mineurs :
– Ils prennent les transactions du bloc
– Ils ajoutent un nombre aléatoire (appelé « nonce »)
– Ils calculent le hash
– Si le hash ne commence pas par assez de zéros, ils changent le nombre et recommencent
– Ils répètent cette opération des milliards de fois par seconde
💪 Pourquoi c’est difficile ?
La difficulté rend la blockchain incassable : pour modifier un ancien bloc, un fraudeur devrait refaire tout ce travail de calcul pour ce bloc ET pour tous les blocs suivants. Avec des milliers d’ordinateurs honnêtes qui continuent à miner en parallèle, le fraudeur n’a quasiment aucune chance de rattraper son retard.
🏆 La récompense
Pour motiver les mineurs à consacrer leur puissance de calcul, le réseau récompense celui qui trouve la solution : il reçoit des bitcoins nouvellement créés ainsi que les frais de transaction. C’est pourquoi on parle de « minage » : comme l’extraction d’or, cela demande un effort pour obtenir une récompense.
📊 Une analogie parlante
C’est comme un puzzle géant : trouver la solution est extrêmement difficile et demande des essais multiples, mais vérifier qu’une solution est correcte est immédiat. N’importe qui peut vérifier en un clin d’œil que le hash commence bien par le bon nombre de zéros. Cette asymétrie entre la difficulté de trouver et la facilité de vérifier est le cœur de la sécurité de la blockchain.
class BlocMine(Bloc):
def miner(self, difficulte):
"""Mine le bloc jusqu'à trouver un hash avec 'difficulte' zéros au début"""
cible = '0' * difficulte
print("⛏️ Minage du bloc ",self.index," en cours...")
while self.hash[:difficulte] != cible:
self.nonce += 1
self.hash = self.calculer_hash()
print("✅ Bloc miné ! Nonce : ",self.nonce)
print(" Hash : ",self.hash)
return self.hash
class BlockchainAvecMinage(Blockchain):
def __init__(self, difficulte=3):
self.difficulte = difficulte
self.chain = [self.creer_bloc_genesis_mine()]
def creer_bloc_genesis_mine(self):
"""Crée un bloc genesis miné"""
bloc = BlocMine(0, ["Genesis Block"], datetime.now(), "0"*64)
bloc.miner(self.difficulte)
return bloc
def ajouter_bloc(self, transactions):
"""Ajoute un nouveau bloc miné à la chaîne"""
nouveau_bloc = BlocMine(index=len(self.chain),transactions=transactions,timestamp=datetime.now(),
hash_precedent=self.dernier_bloc().hash)
nouveau_bloc.miner(self.difficulte)
self.chain.append(nouveau_bloc)
return nouveau_bloc
# Test de la blockchain avec minage
print("🔨 Création d'une blockchain avec preuve de travail")
blockchain_minee = BlockchainAvecMinage(difficulte=3)
print(" " + "= "*60 + " ")
transactions_minage_1 = ["Alice envoie 10 BTC à Bob"]
blockchain_minee.ajouter_bloc(transactions_minage_1)
print("" + "="*60 + "")
transactions_minage_2 = ["Bob envoie 3 BTC à Charlie"]
blockchain_minee.ajouter_bloc(transactions_minage_2)
print("📊 Résumé de la blockchain minée :")
for bloc in blockchain_minee.chain:
print("Bloc #",bloc.index," - Hash : ",bloc.hash[:30],"... (Nonce : ",bloc.nonce,")")
>>> 🔨 Création d'une blockchain avec preuve de travail
⛏️ Minage du bloc 0 en cours...
✅ Bloc miné ! Nonce : 4488
Hash : 0008ce57557625ee1e2a5b3e3c361727aef521a0faf51d49af8b39c5a96257b8
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
⛏️ Minage du bloc 1 en cours...
✅ Bloc miné ! Nonce : 5820
Hash : 000fecdad96efa4641f562063f8a5ef4f406a61a70101d14f47c8c800ed2475d
============================================================
⛏️ Minage du bloc 2 en cours...
✅ Bloc miné ! Nonce : 9652
Hash : 0006e06a5faa2da1c2c219144b6ac590eae43e1285237403aba8c55fc0099dd2
📊 Résumé de la blockchain minée :
Bloc # 0 - Hash : 0008ce57557625ee1e2a5b3e3c3617 ... (Nonce : 4488 )
Bloc # 1 - Hash : 000fecdad96efa4641f562063f8a5e ... (Nonce : 5820 )
Bloc # 2 - Hash : 0006e06a5faa2da1c2c219144b6ac5 ... (Nonce : 9652 )
8. Visualisation des liens entre les blocs
def visualiser_blockchain(blockchain):
"""Crée une visualisation simple de la blockchain"""
data = []
for bloc in blockchain.chain:
data.append({'Index': bloc.index,'Hash (début)': bloc.hash[:15] + '...',
'Hash précédent (début)': bloc.hash_precedent[:15] + '...',
'Transactions': ', '.join(bloc.transactions)[:30] + '...'
if len(', '.join(bloc.transactions)) > 30 else ', '.join(bloc.transactions),
'Nonce': bloc.nonce})
df = pd.DataFrame(data)
return df
print("📋 Vue d'ensemble de la blockchain :")
df = visualiser_blockchain(ma_blockchain)
display(df)
print("🔗 Chaque bloc contient le hash du bloc précédent, créant ainsi une chaîne sécurisée.")
9. Exercices pratiques
Exercice 1 : Comprendre le hachage
Modifie le texte « NSI c’est génial » et observe comment le hash change.
Exercice 2 : Ajouter des transactions
Ajoute 3 nouveaux blocs à ma_blockchain avec des transactions de ton choix.
Exercice 3 : Vérification d’intégrité
Tente de modifier un bloc et explique pourquoi la blockchain détecte la fraude.
Exercice 4 : Jouer avec la difficulté
Modifie la difficulté de minage (3, 4, 5) et observe le temps de calcul.
# Espace pour tes expérimentations !
# Exercice 1 : Teste différents textes
print("🔬 Exercice 1 : Test du hachage")
mon_texte = "NSI c'est génial"
print(f"Hash de '{mon_texte}' : {calculer_hash(mon_texte)}")
# Modifie le texte et observe...
# Exercice 2 : Ajoute tes propres blocs
# ma_blockchain.ajouter_bloc(["Ta transaction ici"])
# Exercice 3 : Teste la modification
# ...
10. Conclusion et points clés à retenir
- Une blockchain est une liste chaînée de blocs
- Le hachage garantit l’intégrité des données
- Chaque bloc contient le hash du précédent (création de la chaîne)
- La moindre modification est détectée
- Le minage (Proof of Work) rend la modification extrêmement coûteuse
Applications réelles :
- Cryptomonnaies (Bitcoin, Ethereum)
- Traçabilité des produits
- Votes électroniques sécurisés
- Contrats intelligents (smart contracts)
- Authentification des œuvres d’art
Pour aller plus loin :