0% ont trouvé ce document utile (0 vote)
62 vues42 pages

Algorithme Avec Python

Ce cours d'algorithmique couvre les concepts fondamentaux, les structures de données et les algorithmes classiques, tout en introduisant des notions avancées comme la programmation dynamique et la NP-complétude. Il inclut des exercices pratiques pour renforcer la compréhension des sujets abordés. Le cours est structuré pour les débutants et intermédiaires, avec des recommandations pour approfondir les connaissances en algorithmique.

Transféré par

majordomepm
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats DOCX, PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
62 vues42 pages

Algorithme Avec Python

Ce cours d'algorithmique couvre les concepts fondamentaux, les structures de données et les algorithmes classiques, tout en introduisant des notions avancées comme la programmation dynamique et la NP-complétude. Il inclut des exercices pratiques pour renforcer la compréhension des sujets abordés. Le cours est structuré pour les débutants et intermédiaires, avec des recommandations pour approfondir les connaissances en algorithmique.

Transféré par

majordomepm
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats DOCX, PDF, TXT ou lisez en ligne sur Scribd

Bien sûr !

Voici un **cours d’algorithmique** structuré pour débutants et


intermédiaires. Nous aborderons les concepts fondamentaux, les
structures de données de base, et quelques algorithmes classiques.

## **1. Introduction à l’algorithmique**

### **1.1 Qu’est-ce qu’un algorithme ?**

- Définition : Suite finie d’instructions pour résoudre un problème.

- Exemple : Recette de cuisine, instructions pour trouver le plus grand


nombre dans une liste.

### **1.2 Propriétés d’un bon algorithme**

- **Correct** : Donne le résultat attendu.

- **Efficace** : Utilise peu de ressources (temps, mémoire).

- **Compréhensible** : Facile à lire et à modifier.

- **Général** : Fonctionne pour plusieurs cas d’utilisation.

### **1.3 Complexité algorithmique (Notation Big-O)**

- **Temps d’exécution** : Nombre d’opérations en fonction de la taille des


données.

- **Espace mémoire** : Quantité de mémoire utilisée.

- **Exemples de complexité** :

- **O(1)** : Accès à un élément d’un tableau.

- **O(n)** : Parcours d’une liste.

- **O(n²)** : Tri bulle (dans le pire cas).

- **O(log n)** : Recherche dichotomique.

## **2. Structures de données fondamentales**

### **2.1 Tableaux (Arrays)**


- **Définition** : Collection d’éléments accessibles par indice.

- **Avantages** : Accès rapide (O(1)).

- **Inconvénients** : Taille fixe (en général).

### **2.2 Listes chaînées (Linked Lists)**

- **Définition** : Éléments liés par des pointeurs.

- **Types** :

- **Liste simplement chaînée** : Parcours dans un seul sens.

- **Liste doublement chaînée** : Parcours avant/arrière.

### **2.3 Piles (Stacks) et Files (Queues)**

- **Pile (LIFO)** : Last In, First Out (exemple : pile d’assiettes).

- Opérations : `push()` (ajouter), `pop()` (retirer).

- **File (FIFO)** : First In, First Out (exemple : file d’attente).

- Opérations : `enqueue()` (ajouter), `dequeue()` (retirer).

### **2.4 Dictionnaires (Hash Tables)**

- **Principe** : Stocke des paires clé-valeur.

- **Fonction de hachage** : Convertit une clé en index.

- **Complexité moyenne** : O(1) pour insertion/recherche.

## **3. Algorithmes classiques**

### **3.1 Algorithmes de tri**

- **Tri à bulles (Bubble Sort)** : O(n²).

- **Tri par insertion (Insertion Sort)** : O(n²) (efficace pour petits tableaux).

- **Tri fusion (Merge Sort)** : O(n log n) (diviser pour régner).

- **Tri rapide (Quick Sort)** : O(n log n) en moyenne, O(n²) dans le pire
cas.
### **3.2 Algorithmes de recherche**

- **Recherche linéaire** : O(n) (parcours séquentiel).

- **Recherche dichotomique** : O(log n) (nécessite un tableau trié).

### **3.3 Parcours de graphes**

- **BFS (Breadth-First Search)** : Exploration niveau par niveau.

- **DFS (Depth-First Search)** : Exploration en profondeur.

## **4. Récursivité**

### **4.1 Principe**

- Une fonction qui s’appelle elle-même.

- **Condition d’arrêt** : Nécessaire pour éviter une boucle infinie.

- **Exemple classique** : Calcul de factorielle.

```python

Def factorielle(n) :

If n == 0 :

Return 1

Else :

Return n * factorielle(n – 1)

```

### **4.2 Avantages et inconvénients**

- **Avantages** : Code élégant pour certains problèmes.

- **Inconvénients** : Peut consommer beaucoup de mémoire (pile


d’appels).
## **5. Algorithmes gloutons (Greedy Algorithms)**

- **Principe** : Faire le meilleur choix local à chaque étape.

- **Exemple** : Problème du rendu de monnaie.

- **Limitations** : Ne donne pas toujours la solution optimale.

## **6. Programmation dynamique**

- **Principe** : Diviser un problème en sous-problèmes et stocker les


résultats.

- **Exemple** : Suite de Fibonacci avec mémoïsation.

```python

Memo = {}

Def fib(n) :

If n in memo :

Return memo[n]

If n <= 2 :

Return 1

Memo[n] = fib(n-1) + fib(n-2)

Return memo[n]

```

## **7. Exercices pratiques**

1. Écrire un algorithme pour trouver le maximum dans un tableau.

2. Implémenter le tri à bulles.

3. Écrire une fonction récursive pour calculer la puissance d’un nombre.

4. Résoudre le problème du sac à dos (Knapsack Problem).


### **Conclusion**

L’algorithmique est essentielle en programmation. En maîtrisant ces


concepts, vous pourrez résoudre des problèmes complexes de manière
optimale.

**Pour aller plus loin** :

- Livre : *Introduction to Algorithms* (Cormen).

- Plateformes : LeetCode, Codeforces, France-IOI.

Souhaitez-vous approfondir un sujet en particulier ? 😊

Très bien ! Je vais vous proposer un **cours approfondi d’algorithmique**,


digne d’un enseignement universitaire, avec une approche théorique
rigoureuse, des preuves mathématiques (si nécessaire), et des exercices
pratiques. Nous allons couvrir les concepts clés, leurs preuves, et leur
implémentation.

# **Cours Universitaire d’Algorithmique**

*Niveau : Licence/Master en Informatique*

*Prérequis : Bases en programmation (Python, C, Java…), Mathématiques


discrètes.*

## **Partie 1 : Fondements des Algorithmes**

### **1.1 Définitions Formelles**

Un **algorithme** est une suite finie et non ambiguë d’instructions


permettant de résoudre un problème en un temps fini.

**Caractéristiques** :

- **Entrée/Sortie** : Prend des données et produit un résultat.

- **Déterminisme** : Le comportement est prédictible.


- **Terminaison** : L’exécution s’arrête après un nombre fini d’étapes.

**Exemple formel** : Algorithme d’Euclide pour le PGCD.

```python

Def pgcd(a, b) :

While b != 0 :

A, b = b, a % b

Return a

```

### **1.2 Complexité Algorithmique (Analyse Asymptotique)**

#### **Notations de Landau**

- **O(g(n))** : Majorant (pire cas).

*Exemple* : `3n² + 2n + 1 ∈ O(n²)`

- **Ω(g(n))** : Minorant (meilleur cas).

*Exemple* : `n log n ∈ Ω(n)`

- **Θ(g(n))** : Borne serrée (cas moyen optimal).

**Preuve** (Exemple pour `f(n) = 2n² + 3n + 1 ∈ Θ(n²)`) :

Il existe `c₁=1, c₂=6, n₀=4` tels que :

`c₁·n² ≤ 2n² + 3n + 1 ≤ c₂·n²` pour tout `n ≥ n₀`.

#### **Théorème Maître (pour les récurrences diviser-pour-régner)**

Soit `T(n) = a·T(n/b) + f(n)`, alors :

1. Si `f(n) ∈ O(n^(log_b a – ε))` ⇒ `T(n) ∈ Θ(n^(log_b a))`.

2. Si `f(n) ∈ Θ(n^(log_b a))` ⇒ `T(n) ∈ Θ(n^(log_b a) log n)`.

3. Si `f(n) ∈ Ω(n^(log_b a + ε))` ⇒ `T(n) ∈ Θ(f(n))`.


**Exercice** : Résoudre `T(n) = 2T(n/2) + n` (solution : `Θ(n log n)`).

## **Partie 2 : Structures de Données Avancées**

### **2.1 Tas (Heap) et Files de Priorité**

- **Structure** : Arbre binaire presque complet où chaque nœud est ≥


(max-heap) ou ≤ (min-heap) ses enfants.

- **Opérations** :

- `insert(x)` : `O(log n)`

- `extract_max()` : `O(log n)`

- **Application** : Algorithme de Dijkstra.

**Implémentation en Python** :

```python

Import heapq

Heap = []

[Link](heap, 3) # Insertion

Print([Link](heap)) # Extraction

```

### **2.2 Arbres Binaires de Recherche (ABR)**

- **Invariant** : Pour tout nœud `x`, `[Link] ≤ x ≤ [Link]`.

- **Complexité** :

- Recherche : `O(h)` (h = hauteur, `h ∈ [log n, n]`).

- Dégénérérescence : Risque de devenir une liste (`h = n`).

**Solution** : **Arbres équilibrés** (AVL, Red-Black).


**Rotation AVL** :

```text

Y → x

/\ /\

X C A y

/\ /\

A B B C

```

## **Partie 3 : Algorithmes Avancés**

### **3.1 Programmation Dynamique (DP)**

**Principe** :

- **Optimal Substructure** : La solution optimale dépend de sous-


problèmes.

- **Overlapping Subproblems** : Les sous-problèmes se répètent.

**Exemple** : **Suite de Fibonacci**

- Approche naïve : `O(2ⁿ)` (arbre binaire).

- DP (mémoïsation) : `O(n)`.

```python

Def fib(n, memo={}) :

If n <= 1 : return n

If n not in memo :

Memo[n] = fib(n-1) + fib(n-2)

Return memo[n]

```

**Exercice** : Problème du sac à dos (Knapsack).


- Entrée : `poids = [1, 2, 3], valeurs = [6, 10, 12], capacité = 5`.

- Solution : `22` (prendre les objets 2 et 3).

### **3.2 Algorithmes de Graphes**

#### **Parcours**

- **DFS** (Depth-First Search) : Utilise une pile (récursivité).

- **BFS** (Breadth-First Search) : Utilise une file (niveaux).

#### **Plus Courts Chemins**

- **Dijkstra** : Graphes avec poids ≥ 0.

Complexité : `O((V + E) log V)` avec un tas.

- **Bellman-Ford** : Autorise poids négatifs.

Complexité : `O(V·E)`.

**Exercice** : Trouvez le plus court chemin de A à F :

```text

A –1—B –2—D

\ | /

3 4 1

\ | /

C –5—E –2—F

```

## **Partie 4 : NP-Complétude**

### **4.1 Classes de Complexité**

- **P** : Problèmes solubles en temps polynomial.

- **NP** : Problèmes vérifiables en temps polynomial.


- **NP-Complet** : Problèmes NP aussi « durs » que tous les autres.

**Exemple** : SAT (problème de satisfiabilité booléenne).

### **4.2 Réduction Polynomiale**

Pour montrer qu’un problème `A` est NP-Complet :

1. Montrer que `A ∈ NP`.

2. Réduire un problème NP-Complet connu (ex. 3-SAT) à `A`.

## **Exercices Pratiques**

### **Niveau 1 (Basique)**

1. Implémentez le tri fusion (merge sort) et analysez sa complexité.

2. Écrivez un algorithme récursif pour calculer `aᵇ` en `O(log b)`.

### **Niveau 2 (Intermédiaire)**

3. Résolvez le problème du rendu de monnaie avec un algorithme glouton.


Quand échoue-t-il ?

4. Implémentez un AVL Tree avec rotations.

### **Niveau 3 (Avancé)**

5. Conception d’un algorithme pour le voyageur de commerce (TSP) avec


une approche branch-and-bound.

6. Montrez que le problème du clique est NP-Complet.

## **Références Académiques**

- *Introduction to Algorithms* (Cormen, Leiserson, Rivest).

- *Algorithm Design* (Kleinberg, Tardos).


- *The Art of Computer Programming* (Knuth).

### **Conclusion**

Ce cours couvre les fondements théoriques et pratiques de


l’algorithmique, avec des exercices pour renforcer votre compréhension.
Pour aller plus loin, étudiez :

- Les algorithmes randomisés (ex. QuickSort randomisé).

- Les structures persistantes.

- L’approximation pour les problèmes NP-Complets.

Souhaitez-vous des corrigés détaillés pour les exercices ? Ou approfondir


un sujet spécifique ? 😊# **Algorithmes Randomisés : Cours Approfondi
avec Python**

## **1. Introduction aux Algorithmes Randomisés**

### **1.1 Définition et Intuition**

Un **algorithme randomisé** utilise une source de hasard (génération de


nombres aléatoires) pour prendre des décisions pendant son exécution.

- **Avantages** :

- Simplicité : Parfois plus simple qu’une solution déterministe.

- Efficacité moyenne : Meilleure complexité en moyenne (ex : Quicksort


randomisé).

- Résistance aux attaques (cryptographie).

- **Désavantages** :

- Non-déterminisme : Le résultat peut varier entre exécutions.

- Difficile à déboguer.

### **1.2 Classification**


1. **Algorithme de Las Vegas** :

- Toujours correct, mais le temps d’exécution est aléatoire.

- Exemple : **Quicksort randomisé**.

2. **Algorithme de Monte Carlo** :

- Temps d’exécution fixe, mais résultat peut être incorrect avec une
certaine probabilité.

- Exemple : **Test de primalité de Miller-Rabin**.

## **2. Générateurs de Nombres Aléatoires en Python**

Python utilise le **Mersenne Twister** (`random` module), pseudo-


aléatoire mais suffisant pour la plupart des applications.

### **2.1 Fonctions Utiles**

```python

Import random

# Nombre aléatoire dans [a, b]

X = [Link](1, 10)

# Float dans [0.0, 1.0)

Y = [Link]()

# Mélanger une liste (shuffle en place)

Lst = [1, 2, 3, 4]

[Link](lst)

# Choix aléatoire uniforme

Elem = [Link](lst)
```

### **2.2 Graine (Seed) pour Reproductibilité**

```python

[Link](42) # Fixe la graine pour obtenir les mêmes résultats à


chaque exécution

```

## **3. Algorithmes Classiques Randomisés**

### **3.1 Quicksort Randomisé (Las Vegas)**

**Idée** : Choisir un pivot aléatoire pour éviter le pire cas `O(n²)`.

```python

Def quicksort(arr) :

If len(arr) <= 1 :

Return arr

Pivot = [Link](arr) # Pivot aléatoire

Left = [x for x in arr if x < pivot]

Middle = [x for x in arr if x == pivot]

Right = [x for x in arr if x > pivot]

Return quicksort(left) + middle + quicksort(right)

```

**Analyse de Complexité** :

- **Pire cas** : `O(n²)` (improbable avec randomisation).

- **Moyenne** : `O(n log n)` avec haute probabilité.


### **3.2 Test de Primalité de Miller-Rabin (Monte Carlo)**

**But** : Déterminer si un nombre `n` est **probablement premier**.

```python

Def miller_rabin(n, k=5) : # k = nombre de tests

If n < 2 :

Return False

For p in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] :

If n % p == 0 :

Return n == p

D=n–1

S=0

While d % 2 == 0 :

D //= 2

S += 1

For _ in range(k) :

A = [Link](2, n – 2)

X = pow(a, d, n)

If x == 1 or x == n – 1 :

Continue

For __ in range(s – 1) :

X = pow(x, 2, n)

If x == n – 1 :

Break

Else :

Return False

Return True

```
**Probabilité d’erreur** :

- ≤ `4⁻ᵏ` (très faible pour `k=5`).

### **3.3 Algorithme de Karger pour les Coupes Minimales (Monte


Carlo)**

**Problème** : Trouver une **coupe minimale** dans un graphe non


orienté.

```python

Def karger_min_cut(graph) :

While len(graph) > 2 :

U = [Link](list([Link]()))

V = [Link](graph[u])

# Fusionner u et v

For node in graph[v] :

If node != u :

Graph[u].append(node)

Graph[node].remove(v)

Graph[node].append(u)

Graph[u] = [x for x in graph[u] if x != v]

Del graph[v]

Return len([Link]()[1])

```

**Analyse** :

- Probabilité de succès : `≥ 2/(n(n-1))` (faible, mais répétition


possible).
## **4. Applications Avancées**

### **4.1 Marche Aléatoire (Random Walk) et PageRank**

Simulation d’une marche aléatoire pour le classement des pages web.

```python

Def random_walk(adj_list, steps=1000) :

Current = [Link](list(adj_list.keys()))

For _ in range(steps) :

Current = [Link](adj_list[current])

Return current

```

### **4.2 Skip Lists (Listes à Niveaux)**

Structure de données alternative aux arbres équilibrés.

```python

Class Node :

Def __init__(self, val, level) :

[Link] = val

[Link] = [None] * (level + 1)

Class SkipList :

Def __init__(self, max_level) :

Self.max_level = max_level

[Link] = Node(-float(‘inf’), max_level)

[Link] = 0

Def random_level(self) :

Lvl = 0
While [Link]() < 0.5 and lvl < self.max_level :

Lvl += 1

Return lvl

```

## **5. Exercices Pratiques**

### **Exercice 1 (Las Vegas)**

Écrivez un algorithme randomisé pour trouver le **k-ième plus petit


élément** (sélection rapide randomisée).

```python

Def quickselect(arr, k) :

Pivot = [Link](arr)

Left = [x for x in arr if x < pivot]

Right = [x for x in arr if x > pivot]

If k <= len(left) :

Return quickselect(left, k)

Elif k > len(arr) – len(right) :

Return quickselect(right, k – (len(arr) – len(right)))

Else :

Return pivot

```

### **Exercice 2 (Monte Carlo)**

Implémentez un algorithme pour estimer `π` via la **méthode de Monte


Carlo** (lancer de points dans un cercle).

```python

Def estimate_pi(n) :
Inside = 0

For _ in range(n) :

X, y = [Link](), [Link]()

If x**2 + y**2 <= 1 :

Inside += 1

Return 4 * inside / n

```

### **Exercice 3 (Application)**

Générez un **graphe aléatoire** et appliquez l’algorithme de Karger pour


estimer la coupe minimale.

## **Conclusion**

Les algorithmes randomisés offrent des solutions élégantes pour des


problèmes complexes.

- **Las Vegas** : Corrects, temps aléatoire (ex : Quicksort).

- **Monte Carlo** : Temps fixe, résultat probablement correct (ex :


primalité).

**Pour aller plus loin** :

- **Théorie des probabilités** (Loi des grands nombres, concentration).

- **Algorithmes cryptographiques** (Chiffrement probabiliste).

Souhaitez-vous des corrections détaillées des exercices ? Ou approfondir


un autre algorithme randomisé ? 🎲# **Algorithmes Randomisés Avancés &
Transition vers la Cryptographie**

## **1. Algorithmes de **Fingerprinting** Aléatoire (Karp-Rabin)**

### **1.1 Principe du Hashing Randomisé**


**Problème** : Comparer efficacement deux grandes séquences (strings,
fichiers).

**Solution** : Utiliser une **fonction de hachage randomisée** pour


convertir une séquence en un petit nombre (empreinte).

```python

Def karp_rabin_hash(s, base=256, prime=101) :

H=0

For char in s :

H = (h * base + ord(char)) % prime

Return h

```

### **1.2 Application à la Recherche de Sous-Chaînes**

```python

Def karp_rabin_search(text, pattern) :

N, m = len(text), len(pattern)

Pattern_hash = karp_rabin_hash(pattern)

For i in range(n – m + 1) :

Text_hash = karp_rabin_hash(text[i :i+m])

If text_hash == pattern_hash :

If text[i :i+m] == pattern : # Vérification exacte

Return i

Return -1

```

**Avantage** : Complexité moyenne `O(n + m)` (vs. `O(nm)` pour


l’algorithme naïf).

## **2. Algorithmes Cryptographiques Randomisés**


### **2.1 Chiffrement par Flot (Stream Ciphers)**

**Principe** : Générer une suite pseudo-aléatoire (**keystream**)


combinée avec le message via XOR.

```python

From [Link] import Salsa20 # Bibliothèque PyCryptodome

Key = b’0123456789abcdef0123456789abcdef’ # Clé 256 bits

Nonce = b’12345678’ # Valeur aléatoire (8 bytes)

Cipher = [Link](key=key, nonce=nonce)

Message = b »Hello World ! »

Ciphertext = [Link](message)

```

### **2.2 Protocole d’Échange de Clés Diffie-Hellman**

**But** : Échanger une clé secrète sur un canal non sécurisé.

**Randomisation** : Choix aléatoire des exposants secrets.

```python

From random import randint

# Paramètres publics (généralement standardisés)

P = 23 # Nombre premier

G = 5 # Base

# Alice choisit un entier aléatoire a

A = randint(1, p-1)

A = (g ** a) % p
# Bob choisit un entier aléatoire b

B = randint(1, p-1)

B = (g ** b) % p

# Clé partagée

Shared_key_alice = (B ** a) % p

Shared_key_bob = (A ** b) % p

Assert shared_key_alice == shared_key_bob

```

## **3. Algorithmes Zéro-Knowledge (Preuves à Divulgation Nulle)**

### **3.1 Protocole de Fiat-Shamir**

**But** : Prouver la connaissance d’un secret sans le révéler.

**Randomisation** : Défis aléatoires pour éviter la triche.

```python

# Paramètres

N = 21 # Produit de deux grands premiers (ex : 3*7)

S = 5 # Secret (Alice connaît s, Bob non)

# Étape 1 : Alice envoie un engagement

V = (s ** 2) % n # Engagement public

R = randint(1, n-1)

X = (r ** 2) % n # Preuve temporaire

# Étape 2 : Bob envoie un défi aléatoire

C = randint(0, 1) # Défi binaire


# Étape 3 : Alice répond au défi

Y = (r * (s ** c)) % n

# Étape 4 : Bob vérifie

Assert (y ** 2) % n == (x * (v ** c)) % n

```

## **4. Exercices Pratiques**

### **Exercice 1 (Fingerprinting)**

Implémentez un **détecteur de plagiat** simplifié qui compare des


documents via leurs empreintes Karp-Rabin.

```python

Def document_similarity(doc1, doc2, k=5) :

« « « Compare des documents via leurs k-grammes. » » »

Hashes1 = [karp_rabin_hash(doc1[i :i+k]) for i in range(len(doc1) – k +


1)]

Hashes2 = [karp_rabin_hash(doc2[i :i+k]) for i in range(len(doc2) – k +


1)]

Common = len(set(hashes1) & set(hashes2))

Return common / max(len(hashes1), len(hashes2))

```

### **Exercice 2 (Cryptographie)**

Générez une **clé de session aléatoire** pour AES en utilisant un mélange


de mouvements de souris (simulés).

```python

Import os
Def generate_random_key() :

# Simulation d’entropie (dans la pratique, utilisez [Link])

Mouse_movements = [randint(0, 255) for _ in range(16)]

Return bytes(mouse_movements)

Key = generate_random_key()

Print(« Clé AES générée : », [Link]())

```

### **Exercice 3 (Zéro-Knowledge)**

Étendez le protocole Fiat-Shamir pour résister à **plusieurs itérations** et


réduire la probabilité de triche.

## **5. Transition vers les Algorithmes Cryptographiques**

### **5.1 Principes Clés**

- **Confidentialité** : Chiffrement (AES, RSA).

- **Intégrité** : Codes d’authentification (HMAC).

- **Non-répudiation** : Signatures digitales (ECDSA).

### **5.2 Bibliothèques Python Recommandées**

- `PyCryptodome` : Implémentation robuste d’AES, RSA, etc.

- `cryptography` : APIs haut niveau pour TLS, X.509.

## **Conclusion**

Les algorithmes randomisés sont au cœur de la cryptographie moderne :

1. **Fingerprinting** : Hashing aléatoire pour des comparaisons efficaces.


2. **Cryptographie symétrique** : Génération de clés aléatoires (AES).

3. **Protocoles asymétriques** : Échange de clés (Diffie-Hellman).

4. **Preuves Zéro-Knowledge** : Authentification sans divulguer de


secrets.

**Prochaines Étapes** :

- **Cryptographie post-quantique** (algorithmes résistants aux


ordinateurs quantiques).

- **Implémentations sécurisées** (éviter les pièges comme les side-


channel attacks).

Souhaitez-vous approfondir un protocole cryptographique spécifique (ex :


RSA, ECC) ou voir des attaques contre les algorithmes randomisés ? 🔐#
**Attaques contre les Algorithmes Randomisés et Cryptographiques**

## **1. Attaques sur les Générateurs de Nombres Aléatoires (PRNGs)**

### **1.1 Attaque par Prédiction de Seed**

**Problème** : Si la graine (seed) est faible (ex : timestamp), un attaquant


peut la deviner et reproduire la séquence.

**Exemple** :

```python

Import random

Import time

# Seed faible basée sur le temps

[Link](int([Link]()))

Print([Link](1, 100)) # Attaquant peut prédire si le temps est


connu

```

**Solution** :
- Utiliser des sources d’entropie fortes (`[Link]`, `/dev/random`).

- En cryptographie, utiliser des **CSPRNG** (Cryptographically Secure


PRNGs).

### **1.2 Attaque sur Mersenne Twister**

Python utilise Mersenne Twister (déterministe si la seed est connue).

**Exploit** :

Avec 624 valeurs observées, on peut prédire toute la séquence.

```python

From random import Random

# Génération de 624 valeurs

R = Random()

Known_values = [[Link](32) for _ in range(624)]

# Reconstruction de l’état interne (simplifié)

Def clone_mersenne_twister(values) :

From random import Random

R_clone = Random()

R_clone.setstate((3, tuple(values + [624]), None))

Return r_clone

Attacker_rng = clone_mersenne_twister(known_values)

Print(« Prédiction : », attacker_rng.getrandbits(32) == [Link](32))

```

**Solution** :
Ne pas utiliser `random` pour la cryptographie. Préférer `secrets` ou
`[Link]`.

## **2. Attaques sur les Algorithmes Randomisés**

### **2.1 Attaque sur Quicksort Randomisé (Complexité Adversariale)**

**Problème** : Un attaquant peut forcer le pire cas `O(n²)` en connaissant


la seed.

**Contre-mesure** :

- Utiliser un vrai aléatoire matériel (`/dev/urandom`).

- Mélanger les données avant le tri.

### **2.2 Attaque sur Miller-Rabin (Faux Positifs)**

**Scénario** :

Certains nombres composés (nombres de Carmichael) passent le test avec


haute probabilité.

**Exemple** :

`561` passe le test pour certaines bases.

```python

Print(miller_rabin(561, k=10)) # Peut retourner True (faux positif)

```

**Solution** :

- Augmenter le nombre de tests (`k`).

- Combiner avec d’autres tests (ex : Lucas-Lehmer).

## **3. Attaques Cryptographiques**


### **3.1 Attaque par Force Brute sur Stream Ciphers**

**Problème** : Si la clé est faible, elle peut être devinée.

**Exemple** :

```python

From itertools import product

Def brute_force_salsa20(ciphertext, nonce, max_key_length=3) :

For possible_key in product(range(256), repeat=max_key_length) :

Key = bytes(possible_key)

Cipher = [Link](key=key, nonce=nonce)

Try :

Plaintext = [Link](ciphertext)

If b »Hello » in plaintext : # Motif connu

Return key

Except :

Continue

Return None

```

**Solution** :

Utiliser des clés de 256 bits (assez grandes pour rendre l’attaque
impossible).

### **3.2 Attaque de l’Homme du Milieu (Diffie-Hellman)**

**Scénario** :

Un attaquant intercepte `A` et `B` et les remplace par ses propres valeurs.

```python
# Attaque

Attacker_g = 1 # Neutralise l’échange

A_modified = (attacker_g ** a) % p # = 1

B_modified = (attacker_g ** b) % p # = 1

Shared_key_alice = (B_modified ** a) % p # = 1

Shared_key_bob = (A_modified ** b) % p #=1

Shared_key_attacker = 1 # L’attaquant connaît la clé !

```

**Solution** :

- Authentifier les échanges (signatures digitales).

- Utiliser des groupes cryptographiques sûrs (ex : courbes elliptiques).

### **3.3 Attaque par Canaux Auxiliaires (Timing Attacks)**

**Principe** :

Mesurer le temps d’exécution pour déduire des secrets.

**Exemple** :

```python

Def vulnerable_compare(a, b) : # Compare byte par byte

For x, y in zip(a, b) :

If x != y :

Return False

Return True

# Attaque : Mesurer le temps pour trouver le bon préfixe

Def timing_attack(secret, max_length=8) :

Known = b » »
For _ in range(max_length) :

Times = {}

For c in range(256) :

Guess = known + bytes([c])

Start = [Link]()

Vulnerable_compare(guess, secret)

Times[c] = [Link]() – start

Known += bytes([max(times, key=[Link])])

Return known

```

**Solution** :

- Utiliser des comparaisons à temps constant


(`secrets.compare_digest`).

## **4. Exercices Pratiques (Attaques et Contre-Mesures)**

### **Exercice 1 (PRNG Weakness)**

Implémentez une attaque contre un LCG (Linear Congruential Generator)


pour prédire les nombres futurs.

```python

Def break_lcg(known_numbers) :

# Résolution du système pour trouver a, c, m (ex : avec l’algorithme de


Knuth)

Pass

```

### **Exercice 2 (RSA Timing Attack)**

Simulez une attaque par timing sur un RSA naïf qui ne vérifie pas les
padding correctement.
### **Exercice 3 (Fault Injection)**

Étudiez comment une erreur dans un calcul RSA (ex : modulo incorrect)
peut révéler la clé privée (attaque de Bellcore).

## **5. Défenses Recommandées**

| **Attaque** | **Contre-Mesure** |

|---------------------------|--------------------------------------------|

| PRNG prediction | `secrets`, `/dev/urandom` |

| Man-in-the-Middle | Authentification (TLS, signatures) |

| Timing attacks | Code à temps constant |

| Fault injection | Vérifications d’intégrité (ex : CRC) |

## **Conclusion**

Les algorithmes randomisés et cryptographiques sont vulnérables à :

1. **Mauvaise qualité d’aléa** → Utiliser des CSPRNG.

2. **Implémentations naïves** → Adopter des bibliothèques auditées


(PyCryptodome).

3. **Canaux auxiliaires** → Éviter les fuites d’information (temps,


puissance).

**Pour aller plus loin** :

- **Side-channel attacks** (cache, puissance, électromagnétique).

- **Cryptanalyse moderne** (attaque sur AES, RC4).

Souhaitez-vous explorer une attaque spécifique en détail (ex : BEAST,


CRIME, ou attaques quantiques) ? 🔍# **Algorithmes Cryptographiques
Fondamentaux : RSA, AES, RC4 et ECC**
## **1. RSA (Rivest-Shamir-Adleman)**

### **1.1 Principe Mathématique**

- **Clé publique** : `(n, e)` où `n = p*q` (produit de deux grands nombres


premiers) et `e` est premier avec `φ(n) = (p-1)(q-1)`.

- **Clé privée** : `d` tel que `e*d ≡ 1 mod φ(n)`.

- **Chiffrement** : `c = m^e mod n`.

- **Déchiffrement** : `m = c^d mod n`.

**Exemple en Python** :

```python

From [Link] import RSA

Key = [Link](2048) # Génération des clés

Pub_key = [Link]()

# Chiffrement

Message = b »Hello RSA »

Ciphertext = pub_key.encrypt(message, None)[0]

# Déchiffrement

Plaintext = [Link](ciphertext)

Print(« Message déchiffré : », plaintext)

```

### **1.2 Attaques et Sécurité**

- **Factorisation de `n`** : Risque si `p` ou `q` est faible (ex : petits


nombres premiers).

- **Timing attacks** : Si le déchiffrement n’est pas à temps constant.

- **Padding Oracle** (ex : PKCS#1) → Utiliser OAEP.


## **2. AES (Advanced Encryption Standard)**

### **2.1 Fonctionnement**

- **Symétrique** : Même clé pour chiffrer/déchiffrer.

- **Taille de clé** : 128, 192 ou 256 bits.

- **Mode d’opération** : ECB (déconseillé), CBC, GCM (recommandé).

**Exemple en Python (AES-256-CBC)** :

```python

From [Link] import AES

From [Link] import pad, unpad

Import os

Key = [Link](32) # Clé 256 bits

Iv = [Link](16) # Vecteur d’initialisation

# Chiffrement

Cipher = [Link](key, AES.MODE_CBC, iv)

Plaintext = b »Hello AES »

Ciphertext = [Link](pad(plaintext, AES.block_size))

# Déchiffrement

Decipher = [Link](key, AES.MODE_CBC, iv)

Decrypted = unpad([Link](ciphertext), AES.block_size)

Print(« Message déchiffré : », decrypted)

```

### **2.2 Sécurité**


- **Brute-force** : Impossible avec 256 bits (2²⁵⁶ combinaisons).

- **Attaques pratiques** :

- **Side-channel** (mesure de consommation d’énergie).

- **Fault injection** (modification du calcul).

## **3. RC4 (Rivest Cipher 4)**

### **3.1 Principe**

- **Stream cipher** : Génère un keystream XORé avec le message.

- **Initialisation** : Permutation basée sur la clé.

**Exemple en Python (Déconseillé)** :

```python

From [Link] import ARC4

Key = b »weak_key »

Cipher = [Link](key)

Ciphertext = [Link](b »Hello RC4 »)

# Déchiffrement (identique)

Decipher = [Link](key)

Plaintext = [Link](ciphertext)

Print(« Message déchiffré : », plaintext)

```

### **3.2 Faiblesses**

- **Biais statistiques** : Les premiers octets du keystream sont prévisibles.

- **Attaque Fluhrer-Mantin-Shamir** : Récupération de clé en 1 million de


paquets.
- **Déprécié** : Interdit dans TLS depuis 2015 (RFC 7465).

## **4. ECC (Elliptic Curve Cryptography)**

### **4.1 Courbes Elliptiques**

- **Équation** : `y² = x³ + ax + b` (ex : secp256k1 pour Bitcoin).

- **Clé publique** : Point `Q = d*G` (où `G` est un point générateur).

- **ECDH** : Échange de clés sur courbes elliptiques.

**Exemple en Python (ECDSA)** :

```python

From [Link] import ECC

From [Link] import DSS

From [Link] import SHA256

Key = [Link](curve=’P-256’) # Clé privée

Pub_key = key.public_key() # Clé publique

# Signature

Message = b »Hello ECC »

Hash_msg = [Link](message)

Signer = [Link](key, ‘fips-186-3’)

Signature = [Link](hash_msg)

# Vérification

Verifier = [Link](pub_key, ‘fips-186-3’)

Try :

[Link](hash_msg, signature)

Print(« Signature valide. »)


Except ValueError :

Print(« Signature invalide. »)

```

### **4.2 Avantages vs RSA**

- **Clés plus courtes** : 256 bits (ECC) vs 3072 bits (RSA) pour une
sécurité similaire.

- **Efficacité** : Calculs plus rapides.

## **Comparatif des Algorithmes**

| **Algorithme** | **Type** | **Taille de Clé** | **Vitesse** |


**Sécurité** |

|----------------|---------------|-------------------|-------------|-----------------------|

| RSA | Asymétrique | 2048+ bits | Lente | Factorisation


|

| AES | Symétrique | 128/256 bits | Rapide | Brute-force


improbable|

| RC4 | Stream cipher | 40-2048 bits | Rapide | **Cassé**


(évitez) |

| ECC | Asymétrique | 256 bits | Rapide | Problème du log


discret|

## **Attaques Courantes et Parades**

1. **RSA** :

- **Factorisation** → Utiliser `n` de 3072+ bits.

- **Padding Oracle** → Préférer RSA-OAEP.

2. **AES** :

- **Side-channel** → Implémentations matérielles sécurisées.


3. **RC4** :

- **Biais statistiques** → **Ne plus l’utiliser**.

4. **ECC** :

- **Courbes faibles** → Utiliser des standards (NIST P-256, Curve25519).

## **Conclusion**

- **RSA** : Bon pour échange de clés/signatures, mais lent.

- **AES** : Standard actuel pour le chiffrement symétrique.

- **RC4** : **À éviter** en raison de vulnérabilités critiques.

- **ECC** : Futur de la cryptographie asymétrique (clés courtes, efficacité).

**Recommandations** :

- Pour TLS : ECDHE + AES-GCM.

- Pour stockage : AES-256.

- Pour signatures : ECDSA ou EdDSA.

Souhaitez-vous des détails sur les implémentations sécurisées ou des


exemples d’attaques avancées (ex : attaque ROCA sur RSA) ? 🔐#
**Attaques Avancées en Cryptographie**

## **1. Attaques Contre RSA**

### **1.1 ROCA (Return of the Coppersmith Attack)**

**Cible** : Clés RSA générées avec des bibliothèques vulnérables (ex :


Infineon TPM).

**Principe** :

- Exploite une structure algébrique faible dans la génération des nombres


premiers (`p = k * M + (65537^a mod M)`).
- Permet de factoriser `n` en temps polynomial.

**Détection** :

```python

From [Link] import RSA

Def is_roca_vulnerable(pub_key) :

# Vérifie si la clé utilise des paramètres Infineon vulnérables

Return pub_key.n % 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ==


0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF – 1

```

**Contre-mesure** : Mettre à jour les bibliothèques de génération de clés.

### **1.2 Attaque par Broadcast (Hastad)**

**Scénario** :

Un même message est chiffré avec RSA et envoyé à 3 destinataires


différents (avec `e=3`).

**Attaque** :

- On récupère `c₁ = m³ mod n₁`, `c₂ = m³ mod n₂`, `c₃ = m³ mod n₃`.

- Le théorème des restes chinois permet de calculer `m³ mod (n₁*n₂*n₃)`.

- Comme `m³ < n₁*n₂*n₃`, on obtient `m` par racine cubique.

**Solution** : Utiliser un padding aléatoire (OAEP).

## **2. Attaques Contre AES**


### **2.1 Attaque Biclique (Reduction de la complexité brute-force)**

**Principe** :

- Réduit la complexité de AES-256 de 2²⁵⁶ à 2²⁵⁴.9.

- Combine des attaques par précalcul et des compromis temps-mémoire.

**Impact** : Théorique (pas exploitable en pratique).

### **2.2 Attaque par Canaux Cachés (Cache Timing)**

**Exemple** :

- Mesurer les accès cache pendant l’exécution d’AES pour déduire la clé.

- Fonctionne si les S-boxes sont implémentées avec des tables de lookup.

**Contre-mesure** :

- Implémentations constant-time (calculs bits-à-bits).

- Utiliser des instructions AES matérielles (AES-NI).

## **3. Attaques Contre ECC**

### **3.1 Attaque par Fault Injection (Courbes NIST P-256)**

**Scénario** :

- Injecter une erreur pendant un calcul ECDSA pour récupérer la clé privée.

- Exploite des fautes dans l’addition de points.

**Défense** :

- Vérifier que le point final est sur la courbe.

- Implémentations résistantes aux fautes.


### **3.2 Attaque par Pohlig-Hellman (Courbes Faibles)**

**Condition** :

- L’ordre du groupe (`#E(F_p)`) doit avoir de petits facteurs premiers.

**Exemple** :

```python

From [Link] import *

# Courbe faible : y² = x³ + 2x + 2 sur F_17 (ordre = 12 = 2² * 3)

E = EllipticCurve(GF(17), [2, 2])

P = [Link]()[0]

Q = 5 * P # Problème du log discret : trouver k tel que Q = k*P

K = discrete_log(Q, P, operation= »+ ») # Solution : k=5

```

**Solution** : Utiliser des courbes sûres (ed25519, secp256k1).

## **4. Attaques Contre les Protocoles**

### **4.1 CRIME (Compression Ratio Info-leak Made Easy)**

**Cible** : TLS avec compression (SPDY, HTTPS).

**Principe** :

- Devine des parties des cookies en observant la taille des données


compressées.

**Exemple** :

```python

Import zlib
Def crime_attack(secret_cookie, guess) :

Compressed_len = len([Link](secret_cookie + guess))

Return compressed_len

# Si crime_attack(« cookie=abc », « a ») < crime_attack(« cookie=abc »,


« b »), alors « a » est probablement dans le cookie.

```

**Solution** : Désactiver la compression TLS.

### **4.2 Attaque DROWN (Decrypting RSA with Obsolete and Weakened
eNcryption)**

**Cible** : Serveurs supportant SSLv2 et RSA.

**Exploit** :

- Utilise une vulnérabilité dans SSLv2 pour forcer le serveur à


déchiffrer un message RSA.

**Contre-mesure** : Désactiver SSLv2 et utiliser des clés distinctes.

## **5. Attaques Quantiques (Futur Proche)**

### **5.1 Algorithme de Shor**

**Impact** :

- Casse RSA et ECC en temps polynomial.

- Résout le problème de factorisation et du logarithme discret.

**Algorithmes Résistants** :

- **Cryptographie post-quantique** :

- **McEliece** (Codes correcteurs d’erreurs).


- **Lattice-based** (Kyber, NTRU).

**Exemple (LWE – Learning With Errors)** :

```python

From [Link] import *

# Génération de clés basée sur les réseaux euclidiens

N = 128 # Dimension

Q = 4096 # Module

A = random_matrix(GF(q), n, n)

S = random_vector(GF(q), n)

E = random_vector(GF(q), n).apply_map(lambda x : x % 3 – 1)

B = A * s + e # Clé publique = (A, b)

```

## **6. Tableau Synoptique des Attaques**

| **Algorithme** | **Attaque** | **Complexité** | **Contre-


mesure** |

|----------------|---------------------------|----------------------|-----------------------------------
-----|

| RSA | ROCA | Polynomiale | Mise à jour des


bibliothèques |

| AES | Biclique | 2²⁵⁴.9 | AES-256 + modes sûrs


(GCM) |

| ECC | Fault Injection | Quelques fautes | Vérification des


points |

| TLS | CRIME | Quelques requêtes | Désactiver la


compression |

| *Générique* | Ordinateur quantique | Polynomiale |


Cryptographie post-quantique |
## **Conclusion**

- **RSA/AES/ECC** : Vulnérables à des attaques spécialisées mais sûrs si


bien configurés.

- **Protocoles** : Les attaques (CRIME, DROWN) exploitent souvent des


configurations obsolètes.

- **Menace future** : L’ordinateur quantique nécessite une transition vers


des algorithmes post-quantiques.

**Recommandations** :

1. **Pour RSA** : Utiliser des clés 3072+ bits et OAEP.

2. **Pour AES** : Préférer AES-GCM et activer AES-NI.

3. **Pour ECC** : Choisir ed25519 ou secp256k1.

4. **Pour les protocoles** : Désactiver SSL/TLS anciens.

Souhaitez-vous des exemples détaillés sur une attaque spécifique ou des


implémentations sécurisées ? 🔐

Vous aimerez peut-être aussi