Skip to content

Commit 0f67ca4

Browse files
author
sacha
committed
ready for publication fontain post
1 parent 8ff9761 commit 0f67ca4

File tree

3 files changed

+75
-64
lines changed

3 files changed

+75
-64
lines changed

content/fontain.md

Lines changed: 75 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,80 @@
1-
Title: Transferer un gros fichier avec une fontaine de QR code
1+
Title: Transférer un fichier via une fontaine de QR code
22
Slug: code-fontain
3-
Date: 2024-09-30 19:30:31
4-
Modified: 2024-09-30 19:30:31
3+
Date: 2024-10-28 19:30:31
4+
Modified: 2024-10-28 19:30:31
55
Tags: algorithme
66
Category: informatique
77
Author: Sacha schutz
8-
SIDEBARIMAGE:images/common/term_banner.jpeg
8+
SIDEBARIMAGE:images/common/fontain_banner.png
99

1010

11-
Serait il possible d'envoyer un fichier de 10 Mo en utilisant uniquement des QR codes ?
12-
C'est la question que je me suis posé lorsque l'on m'a affirmé qu'il n'était
13-
pas possible d'extraire des données d'une instance Jupyter tournant dans un bureau virtuel.
14-
Dans cette bulle, un datascientist est censé pouvoir faire des analyses mais il lui est impossible
15-
de récupérer des données.
16-
Cependant, les données qui s'affiche sur un écran transitent forcement par la carte graphique de l'utilisateur.
17-
Un hacker pourrait donc très probablement récupérer l'intégralité d'un gros fichier en faisant
18-
juste des captures d'écran. J'ai donc voulu tester cette théorie en essayant de transferer un fichier de 10 Mo
19-
à partir d'une vidéo d QR codes générés grâce à un algorithmes très interessant : Le code fontaine de Luby.
11+
Serait-il possible d’envoyer un fichier de 10 Mo en utilisant uniquement des [QR codes](https://fr.wikipedia.org/wiki/Code_QR) ? C’est la question que je me suis posé lorsque l’on m’a affirmé qu’il était impossible d'extraire des données d’une instance [Jupyter](https://fr.wikipedia.org/wiki/Jupyter) fonctionnant dans un [bureau virtuel](https://fr.wikipedia.org/wiki/Bureau_virtuel_(travail)).
2012

13+
Dans cet genre d'environnement, un data scientist est censé pouvoir effectuer des analyses, mais il lui est impossible de récupérer les données. Cependant, les données affichées à l’écran transitent forcément par la carte graphique de l’utilisateur, ce qui signifie qu’un pirate pourrait potentiellement récupérer l’intégralité d’un fichier volumineux en réalisant simplement des captures d’écran.
14+
15+
J’ai donc voulu tester cette théorie en tentant de transférer un fichier de 10 Mo à partir d’une séquence vidéo de QR codes, générée grâce à un algorithme particulièrement ingénieux : [le code fontaine de Luby](https://en.wikipedia.org/wiki/Luby_transform_code).
2116

2217
## Encoder des données dans un QR Code
2318

24-
La capacité de stockage d'un QR code varie en fonction de sa version et de son niveau de code d'erreur.
25-
Dans le meilleurs des cas, nous allons pouvoir stocker 2953 octects en version 40 ( 177 x 177 )
26-
en utilisant un niveau de correction d'erreur Low ( 7% ).
27-
Nous sommes loin des 10 Mo souhaités. Pour y rémedier il va donc falloir généré plein de QR code que l'on
28-
pourra transmettre dans une vidéo. Supposions que je génère 30 QR code par secondes, je pourrais récupérér
29-
des données à une vitesse de 720 Kbits/s (3000 * 30 * 8 * 10**-3) de quoi faire pallir mon bon view modem 56K.
30-
Et voilà ce que ça donne pour un fichier de 10 Ko.
19+
La capacité de stockage d’un QR code varie en fonction de sa version et de son niveau de correction d'erreur. Dans le meilleur des cas, un QR code en version 40 (177 x 177) avec un niveau de [correction d'erreur](https://dridk.me/reed-solomon.html) faible (7 %) peut stocker jusqu’à 2 953 octets. Nous sommes encore loin des 10 Mo souhaités. Pour y remédier, il est donc nécessaire de générer plusieurs QR codes, que l’on pourra transmettre en masse dans un flux en stream ou via une vidéo.
20+
21+
Supposons que je génère 30 QR codes par seconde ; je pourrais ainsi récupérer des données à une vitesse de 480 Kbits/s (2 000 octets * 30 * 8 * 10⁻³). On est certes loin des vitesses de la fibre optique, mais au-dessus des performances d’un modem 56K.
3122

3223
<div class="figure"><img src="images/fontain/qrfontain.gif" /><div class="legend">
33-
Animation d'un QR Code en version 40 encodant un fichier de 100 Ko.
24+
Animation à 30 frame par secondes de plusieurs QR code en version 40 encodant un fichier de 100 Ko.
3425
</div>
3526
</div>
3627

3728

3829
## Utilisation du code fontaine
39-
Placons nous maintenant du coté du recepteur. Il suffirait en principe de faire des capture d'ecran toutes
40-
les 4 ms et décoder chaque QR Code dans le bon ordre. Mais en réalité, il y a de forte chance d'en rater certain.
41-
Dans des protocoles classiques de communication réseau bi-directionnel comme TCP/IP, chaque capture ou paquet doit
42-
être confirmer à l'emetteur avant de recevoir le prochain. Dans notre cas, ce n'est pas possible
43-
car la communication est unidirectionnel, nous ne faisons qu'écouter.
44-
Une solution serait donc de demander à l'emetteur de répéter en boucle son message. Mais attendre un tour complet
45-
pour récupérer un seul paquet risque d'être long.
46-
La solution c'est d'utiliser un code fontaine, qui consiste à générer aléatoirement des paquets de données labelisé
47-
et les emettre constamment comme une "fontaine de paquet". Le recepteur aura juste à collecter les paquets
48-
dans le desordre puis les réassembler. Une implementation très bien optimisé du code fontaine est le code de transformation
49-
de Luby ou code LT
30+
Plaçons-nous maintenant du côté du récepteur. En principe, il suffirait de faire des captures d’écran toutes les 4 ms pour décoder chaque QR code dans le bon ordre. Mais en pratique, il est très probable que certains QR codes soient manqués. Dans les protocoles classiques de communication réseau bidirectionnelle, comme [TCP](https://fr.wikipedia.org/wiki/Transmission_Control_Protocol), chaque capture ou [paquet](https://fr.wikipedia.org/wiki/Paquet_(r%C3%A9seau)) doit être confirmé par le récepteur avant d’envoyer le suivant. Ici, ce n’est pas envisageable, car notre communication est unidirectionnelle : nous ne faisons qu’écouter.
31+
32+
Une solution pourrait consister à demander à l'émetteur de répéter son message en boucle. Cependant, attendre un cycle complet pour récupérer un seul paquet manqué serait inefficace.
33+
34+
La solution réside dans l'utilisation d'un [code fontaine](https://fr.wikipedia.org/wiki/Code_d%27effacement#Codes_fontaine_quasi-optimaux) qui génère des paquets de données aléatoires, étiquetés, qui sont émis continuellement comme une *fontaine de paquets*. Le récepteur n’a alors qu’à collecter les paquets dans le désordre et les réassembler.
35+
36+
Il existe une implémentation de code fontaine très efficace, appelée [transformation de Luby](https://en.wikipedia.org/wiki/Luby_transform_code) (ou code LT), que nous allons utiliser. Voici comment elle fonctionne.
5037

5138
### Fonctionnement de l'algorithme de Luby
5239

5340
Un code LT fonctionne de la façon suivante:
5441

5542
#### Emetteur
56-
- Le message à transmettre est d'abord découpé en plusieurs bloc source de la même taille.
57-
- Un tirage aléatoire est ensuite réalisé pour selectionné N bloc source.
58-
- Ce tirage aléatoire suit une distribution de Soliton. ( Voir image )
59-
- Ces N blocs sources sont combiné ensemble avec un operateur XOR pour former un seul bloc.
60-
- Ce bloc encodé est alors transféré au recepteur en précisant le nombre de bloc source qu'il contient dans un identifiant.
61-
- Dans notre cas, ce bloc est transféré via un QR code en reservant les 12 premiers bytes pour l'identifiant.
43+
44+
- Le message à transmettre est d'abord découpé en plusieurs blocs source de même taille.
45+
- Un tirage aléatoire est ensuite effectué pour sélectionner N blocs source.
46+
- La valeur de N est choisie selon une distribution de [Soliton](https://en.wikipedia.org/wiki/Soliton_distribution) (voir graphique ci-dessous).
47+
- Ces N blocs source sont combinés à l’aide de l’opérateur [XOR](https://fr.wikipedia.org/wiki/Fonction_OU_exclusif) pour former un seul bloc encodé.
48+
- Ce bloc encodé est ensuite transmis au récepteur avec un identifiant précisant le nombre de blocs source qu’il contient.
49+
- Dans notre cas, ce bloc est transféré via un QR code, les 12 premiers octets étant réservés pour l’identifiant.
6250

6351
<div class="figure"><img src="images/fontain/soliton.png" /><div class="legend">
64-
Distribution de Soliton. Notez qu'en suivant cette distribution, il y aura principalement des combinaisons de 2 blocs
65-
et qque fois des blocs seuls, essentielle pour pouvoir faire les premiers XOR.
52+
Distribution de Soliton utilisé pour choisir le nombre de bloc source à combiner.
53+
Notez qu'il y aura principalement des combinaisons de 2 blocs et plus rarement des blocs seuls.
54+
6655
</div>
6756
</div>
6857

6958

7059
#### Recepteur
71-
- Le recepteur collecte les paquet encodé en scannant les QR code
72-
- Si le paquet est composé d'un bloc source il le met de coté
73-
- Si le paquet est composé de 2 bloc source, il fera un XOR avec un des paquet déjà recu pour reconstruire le second paquet source.
74-
- Il procède ainsi de suite avec des paquets composés de 3,4..N bloc sources.
75-
- Lorsqu'il a reçu tout les paquets, il les remet dans l'ordre pour reconstruire le message original.
7660

77-
En combinant les blocs avec un XOR, cela nous permet d'envoyer statistiquement beaucoup moins de bloc que la méthode naïves
78-
qui consisterai à les envoyer un par un.
61+
- Le récepteur collecte les paquets encodés en scannant les QR codes.
62+
- Si un paquet est composé d’un seul bloc source, il le stocke directement.
63+
- Si un paquet est composé de 2 blocs source, il applique un XOR avec un des paquets déjà reçus pour reconstruire le second bloc source.
64+
- Il poursuit de cette manière avec les paquets contenant 3, 4 ... blocs
65+
- Une fois tous les paquets reçus et reconstruits, il les remet dans l’ordre pour reconstruire le message original.
7966

80-
Une implementation de cette librarie est disponnible pour python à cette adresse.
67+
En combinant les blocs avec un XOR, on peut transmettre statistiquement beaucoup moins de blocs que la méthode naïve,
68+
qui consisterait à les envoyer un par un.
8169

70+
Une implémentation de cet algorithme est disponible dans la bibliothèque [lt-code](https://github.com/anrosent/LT-code) en Python.
8271

83-
## Mise en place
8472

85-
Avec tous ces ingrédients, j'ai construit une petit librarie me permettant de transférer des données
86-
via des QR code. Le code source est disponnible sur https://github.com/dridk/qrfontain.
73+
## Implementation en python
8774

88-
### Pour emettre
75+
Avec tous ces éléments, j'ai développé une petite librarie disponnible sur Github appelée [qrfontain](https://github.com/dridk/qrfontain/) qui permet de transférer des données via une flux de QR codes.
76+
77+
### Pour emettre un fichier
8978

9079
```python
9180
import qrfontain
@@ -96,7 +85,7 @@ with open("big.txt", "rb") as file:
9685
display(image)
9786

9887
```
99-
### Pour recevoir
88+
### Pour recevoir un fichier
10089

10190
```python
10291
import qrfontain
@@ -109,28 +98,50 @@ with open("output.txt", "wb") as file:
10998

11099
```
111100

112-
### Recepteur
113-
Pour le recepteur, j'ai egallement crée une petite application graphique en Qt.
114-
J'utilise QScreen.grabWindow pour faire des screenshots et zbarlight pour la capture des qrcode.
115-
L'application me permet de selectionner une région de mon bureau avec un carré transparent pour
116-
capturer les QR codes et télécharger les données.
101+
### Experience
102+
103+
Pour l'expérience, j'ai créé trois fichiers de tailles différentes (100 Ko, 1 Mo et 10 Mo) que j'ai encodés dans une vidéo de QR codes à 30 images par seconde.
104+
Pour le décodage, j'ai développé une interface graphique en [Qt](https://doc.qt.io/qtforpython-6/) capable de capturer des QR codes à 60 fps. J'utilise [QScreen.grabWindow](https://doc.qt.io/qt-6/qscreen.html#grabWindow) pour prendre des captures d'écran et [zbarlight](https://github.com/Polyconseil/zbarlight) pour la détection des QR codes. L'application permet de sélectionner une région de l’écran via un carré transparent pour capturer les QR codes et récupérer les données transmises. Voir la vidéo ci-dessous. C'est assez satisfaisant, on a l'impression de récupérer un signal radio extra-terreste.
117105

118-
<video width="600px" controls>
106+
107+
<center>
108+
<video width="600" controls>
119109

120110
<source src="images/fontain/gui_receiver.webm" type="video/webm" />
121111

122112
</video>
123-
113+
</center>
124114

125115
### Resultats
126116

127-
Sur mon PC :
128-
500 ko
129-
1 Mo
130-
10 Mo
117+
Et voilà les temps de téléchargement pour 3 fichiers de tailles différentes :
118+
119+
- 0.1 Mo : 9446 ms
120+
- 1 Mo : 50464 ms
121+
- 10 Mo : 466420 ms
122+
123+
Il me faut donc 7 minutes pour télécharger un fichier de 10 Mo.
124+
La relation est linéaire avec une vitesse avoisinant les 180 kbits/s soit 3 fois plus rapide
125+
qu'un modem 56K.
131126

132127
### Conclusion
133128

129+
Avec un peu plus d'effort, je pense qu'il serait facile de transmettre des données plus rapidement.
130+
Nous pourions par exemple jouer avec le framerate ou en parallelisant avec plusieurs QR code.
131+
Après nous serons toujours limités par la bande passante et le taux de rafraichissement d'une image.
132+
133+
J'avais au début envisagé de transmettre les données en utilisant les pixels et les couleurs d'une image.
134+
Cependant, il est très difficile de récupérer les informations de manière fiable à partir d'une capture d'écran.
135+
L'antialiasing et les transformations de rendu déforment les données encodées, rendant leur décodage impraticable.
136+
Si vous avez des idées, je suis preneur ! N’hésitez pas à les partager dans les commentaires !
137+
138+
## Reference
139+
140+
- [qrfontain](https://github.com/dridk/qrfontain/tree/main?tab=readme-ov-file): Ma petite librarie python
141+
- [divan.dev](https://divan.dev/posts/fountaincodes) : blog de de Divan que j'ai découvert après !
142+
- [Nick's Blog](http://blog.notdot.net/2012/01/Damn-Cool-Algorithms-Fountain-Codes) : Damn Cool Algorithms: Fontain Codes
143+
- [qram](https://github.com/digitalbazaar/qram) : Implementation en Javascript
144+
134145

135146

136147

834 KB
Loading
-1.9 MB
Binary file not shown.

0 commit comments

Comments
 (0)