Les nouvelles technologies pour l’enseignement des mathématiques
Intégration des TICE dans l’enseignement des mathématiques

MathémaTICE, première revue en ligne destinée à promouvoir les TICE à travers l’enseignement des mathématiques.

Introduction à la Blockchain
Article mis en ligne le 28 mars 2026

par Benjamin Clerc

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.

C’est quoi une base de données distribuée ?

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

AspectBase de données classiqueBase 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

SHA256 : Le moteur de hachage de la blockchain

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)

Le Timestamp (Horodatage) expliqué simplement

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 !

Le minage et la preuve de travail expliqués simplement

⛏️ 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 :