ĞMixer – anonymiseur de transactions sûr et distribué

silkaj
python
duniterpy

#13

Tu utilises quelle version de DuniterPy ?

Sur la branche master il y a un commit en plus que sur dev pour installer une ancienne version compatible de DuniterPy.


#14

La 0.52.0, la dernière sur pip.


#15

Ok, spotted.


#16

Hop, petit compte-rendu de l’avancement du projet :

  • On peut envoyer une requête de mixage, elle arrive bien jusqu’au dernier nœud
  • Les nœuds renvoient bien leur confirmation
  • On peut mettre une liste de plusieurs serveurs BMA, au cas où un ne fonctionne pas
  • Si un nœud a une requête à envoyer à un nœud hors-ligne, il ré-essaiera jusqu’à ce que ça marche

Trucs manquants : (barré = fait)

  • Quelques tests de sécurité (pour éviter une erreur qui ferait arrêter le processus ou un remplissage de la mémoire)
  • Une meilleure gestion de la découverte du réseau
  • Une date d’expiration pour les confirmations de mixage
  • Gérer les transactions dans la monnaie
  • Annuler une requête de mixage si la date est expirée, renvoyer la transaction si elle a été reçue
  • Le client doit dire au nœud d’entrée qu’il est un client, et non un nœud
  • Le nœud d’entrée doit pouvoir envoyer les confirmations au client (soit en attendant un ping du client, soit avec un websocket mais je n’ai jamais fait ça, ni en Python ni en JS)
  • Faire un vrai client (en JS dans le navigateur de préférence)
  • Documenter le protocole de façon claire, en anglais et français (schémas)
  • Attendre un accusé de réception avant de supposer que le nœud qu’on a contacté a bien reçu la requête

Voilà, cette liste est surtout pour moi, mais si quelqu’un voudrait participer ça serait avec plaisir aussi !

Sinon pour la découverte du réseau, pour le moment j’opère comme suit : à intervalle régulier, Alice ping tous les nœuds qu’elle connaît pour leur demander leur liste de nœuds connus et qu’ils la rajoutent dedans si ce n’est pas déjà fait. On obtient donc un réseau où chaque nœud connaît tous les autres. Pour éviter d’avoir à pinger 5000 nœuds, on met une limite à 30 connexions. Donc si le réseau contient 30 nœuds connectés, et que Bob veut se connecter, il ne pourra pas.

Il serait peut-être possible de ne se connecter qu’à certains nœuds connus, aléatoirement. Mais il faut que chaque nœud aie la correspondance complète pubkey->host:port. Comment ce mécanisme est géré dans Duniter-ts ?


#17

Dans Duniter les nœuds s’échangent quasi constamment les fiches de peer qu’il connaissant avec tout les autres nœuds auxquels ils sont connecté,une fiche de peer ressemble à ça :

{
  "version": 10,
  "currency": "g1",
  "endpoints": [
    "MONIT_API g1-monit.librelois.fr 443",
    "BASIC_MERKLED_API ts.g1.librelois.fr 443",
    "WS2P c1c39a0a ts.g1.librelois.fr 443 /ws2p",
    "BMATOR 3k2zovlpihbt3j3g.onion 80",
    "WS2PTOR 1be86653 3k2zovlpihbt3j3g.onion 20901",
    "WS2PTOR d0a2cfcc toefa6zlbcyvqzlg.onion 20901"
  ],
  "status": "UP",
  "block": "205080-000001D1E10E6A7659B00C25EDCA15E61FBD52787FA65BC3144427C69D7F557F",
  "signature": "YrjWVAG48G5kH/ixTwOCuMYspi0It6I9QRYREuONkpJhwkyIUkQOW/WCXO6QHGsopALw8Q4g8QTo7pxrYxS8Dg==",
  "raw": "Version: 10\nType: Peer\nCurrency: g1\nPublicKey: D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx\nBlock: 205080-000001D1E10E6A7659B00C25EDCA15E61FBD52787FA65BC3144427C69D7F557F\nEndpoints:\nMONIT_API g1-monit.librelois.fr 443\nBASIC_MERKLED_API ts.g1.librelois.fr 443\nWS2P c1c39a0a ts.g1.librelois.fr 443 /ws2p\nBMATOR 3k2zovlpihbt3j3g.onion 80\nWS2PTOR 1be86653 3k2zovlpihbt3j3g.onion 20901\nWS2PTOR d0a2cfcc toefa6zlbcyvqzlg.onion 20901\nYrjWVAG48G5kH/ixTwOCuMYspi0It6I9QRYREuONkpJhwkyIUkQOW/WCXO6QHGsopALw8Q4g8QTo7pxrYxS8Dg==\n",
  "pubkey": "D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx"
}

C’est un document signé cryptographiquement qui contiens tout les endpoints du node, c’est cela qui garanti la correspondance complète pubkey -> host:port.

Chaque noeud génère sa propre fiche de peer a son démarrage (et a chaque changement de sa config réseauà puis la distribiue a tout les noeuds auquel il est connecté.

Les fiches de peer sont datés (via blockstamp), pour pouvoir élaguer les anciennes fiches de peer, du coup chaque nœud doit recréer sa fiche de peer a intervalle régulier (par exemple toutes les heures) pour qu’elle ne soit pas élaguée.

Les fiches de peer actuelle du protocole WS2pv1 (Appliqué par Duniter-ts et aussi en partie par Durs) contiennent un champ qui ne sert plus (status) et qui est lié au fait qu’historiquement la couche réseau inter-nœud était gérée par un crawler BMA qui n’est plus de tout utilisé depuis duniter 1.6.

Pour WS2Pv2 la fiche de peer contiendra un champ supplémentaire : le UUID. C’est un nombre aléatoire sur 4 octets, ce qui permettra d’identifier de manière unique un nœud du réseau par son couple (UUID-pubkey), ce n’est pas le cas aujourd’hui car certains nœuds ont la même pubkey.

Concernant la connexion aux autres nœuds, oui il faut un quota, et pour que ça marche bien il faut un perturbateur : couper aléatoirement 1 connexion toutes les X minutes (il me semble avoir mis ça en place dans Duniter), une sorte de bazar aléatoire indispensable a la vie, sinon tout peut se figer et certaines partie du réseau s’isoler complètement.


#18

Attention, pour Sakia, il faut rester sur la dernière 0.4x.x de Duniterpy, surtout pas la 0.52.x !

J’ai ajouté la limitation de version dans les requirements de pip sur le dépôt, comme l’a signalé @moul (bien vu !).

Mais du coup l’ancienne version de Duniterpy… ne t’en inspire pas ! :slightly_smiling_face:


#19

C’est bon, j’ai pu faire une transaction ! :partying_face:
Finalement j’ai utilisé silkaj (tx.generate_and_send_transaction), qui est plus simple que sakia et plus facile à prendre comme bibliothèque.


#20

Bravo @tuxmain ! Je te dois te dire que ton investissement me réchauffe le coeur ! :slight_smile:
j’aime bien voir des gens qui développe des trucs jusqu’au bout.

#OnContinue #Courage !


#21

En effet, c’est rare que je termine un projet que j’ai commencé…

Mais là ça marche ! C’est très satisfaisant, la première transaction ĞMixée automatiquement en oignon a été réalisée entre mon compte et celui-ci. Bien sûr, il reste encore quelques fonctionnalités à ajouter dans le serveur, notamment le retour des transactions, et plein de tests de sécurité pour éviter un crash dû à une erreur.

Il reste aussi la rémunération des nœuds. Soit on se met d’accord sur une taxe fixe que chaque nœud prend sur la transaction (donc avec une taxe à 1 Ğ1, une transaction de 100 Ğ1 passant par 3 nœuds sera de 97 Ğ1 en sortie), mais cela peut poser des problèmes d’anonymat (on peut tracer plus facilement les transactions puisqu’on sait par combien de nœuds elle est passée, enfin peut-être que ça ne pose pas de problème) ; soit on n’applique pas de taxe mais on crée un double de Remuniter pour cela.


#22

En fait je comprend pas bien comment ça fonctionne… parce que là les junes ne sont pas anonymes :thinking:
on remonte facilement à la source via les transactions…


#23

On peut choisir le nombre minimal de transactions pour mixer, par défaut c’est 5 mais pour le test j’en ai mis une seule (parce qu’attendre 20 minutes que chaque transaction soit enregistrée c’est déjà long pour le test). Quand j’aurai réinstallé mon Raspberry Pi, j’y mettrais des instances de test publiques, et ça serait sympa si d’autres gens pouvaient en faire tourner aussi, pour tester avec plus de nœuds et plus de transactions.


#24

On peut en mettre 20, on pourra toujours remonter à la source, non ?


#25

Comment ?

Seuls le nœud A et le client d’origine savent associer une transaction que reçoit A et une qu’il envoie, grâce aux commentaires.


#26

Bonjour,

S’il y a une sorte de remu-Gmixer, est-ce possible d’appliquer une taxe une fois par transaction (p.ex entrée ou sortie) qui l’enverrait sur le compte de répartition ? Cela aurait-il des conséquences pour le “suivi” des transactions ?


#27

C’est une bonne idée. En fait, on peut toujours savoir si une transaction est en entrée ou en sortie, puisque l’envoyeur ou le récepteur n’est pas un nœud. Donc on peut toujours savoir où se situe une transaction (envoyeur-1 ou 1-2 ou 2-3 ou 3-receveur), la seule incertitude est quand elle est au milieu (1-2 ou 2-3). Cette incertitude offre 2 possibilités pour un chemin de 3 nœuds. Pour compliquer la chose, on pourrait faire aléatoirement un chemin de 3 ou de 4 nœuds (je n’ai pas calculé les probabilités donc je ne sais pas si ça serait significativement intéressant).

Comment choisir qui est rémunéré ? À quel montant ? Un propriétaire de nœud pourrait faire passer uniquement ses propres transactions et pas les autres par son nœud, donc recevoir la rémunération alors qu’il ne devrait pas.

Edit: Si vous voulez tester, vous pouvez ajouter cette ligne dans le fichier peers pour le connecter à mon nœud :

4QRZj4bHpXTdJajfX8mTf2RmYQhKX7BtiMiZL3z5Lo8F 86.234.239.147 10951

#28

Peut-être que tu pourrais déplacer le dépôt de ĞMIxer à l’adresse https://git.duniter.org/clients/python/ĞMixer
Car il utilise Silkaj et DuniterPy et est écrit en Python. De plus, c’est un client Duniter.

Je vois que tu utilises Silkaj 0.6.1 qui n’utilise pas DuniterPy.
À partir de Silkaj 0.7.0, ça utilise DuniterPy, et par conséquent, le code est asynchrone.
Dans ton code, je vois des parties, ou débuts d’asynchrone. Tu seras prêt pour l’y intégrer.

Autre, jette un coup d’œil à pipenv. Ça sera plus propre pour gérer les dépendances.

Si tu as besoin d’aide avec le code de Silkaj ou DuniterPy ou tout autre sujet relatif à l’environnement ou le langage Python n’hésite pas.


#29

Pour déplacer le dépôt c’est dans " Rename repository" ?

Je crois que je ne me servirai pas de l’asynchrone, du coup j’aurai juste besoin de mettre des await partout.

Je verrai plus tard pipenv…


#30

Voilà j’ai enfin réussi à configurer correctement mon réseau… Maintenant c’est compatible avec IPv6.

Si vous voulez héberger une instance, pour pouvoir tester à la fois la gestion des connexions et les transactions :

sudo apt install libsodium-dev python3 python3-pip
sudo pip3 install libnacl duniterpy silkaj
sudo pip3 install python2_secrets # seulement si Python < 3.6

git clone https://git.duniter.org/tuxmain/gmixer-py.git
cd gmixer-py
python3 server.py -i
nano ~/.gmixer/config.ini
# changez Host si nécessaire avec votre IP
echo "4QRZj4bHpXTdJajfX8mTf2RmYQhKX7BtiMiZL3z5Lo8F 2a01:cb19:982:f800:ec34:6087:5197:4752 10951" >> ~/.gmixer/peers
echo "FE4p3w7LvfDtat7pwNky5vZ9SPGKRrFid8gS2bg8Pjka 2a01:cb19:982:f800:ec34:6087:5197:4752 10952" >> ~/.gmixer/peers
python server.py -s

Le programme ne gère pas l’upnp donc il faudra probablement toucher aux NAT/PAT et pare-feu de votre box/routeur. C’est TCP et port par défaut 10951.

Pour voir les infos sur un nœud, il y a une magnifique API qui permet notamment d’avoir la liste des pairs : http://[2a01:cb19:982:f800:ec34:6087:5197:4752]:10951/list/pubkey/version (le forum ne veut pas reconnaître le lien à cause de l’IPv6)


#31

Voilà le compte-rendu de l’avancement :

  • Les données chiffrées sont désormais en binaire plutôt qu’en hexa (grâce à la màj de duniterpy) ;
  • Le client se connecte à un nœud pour récupérer la liste des nœuds et construit un chemin composé de n nœuds aléatoires ;
  • La liste des transactions est enregistrée dans une bdd LevelDB, donc si le nœud est redémarré il peut continuer de traiter les transactions en cours ;
  • Répondre un accusé de réception pour pouvoir renvoyer la requête si il y a un problème réseau ;
  • Utiliser ubjson plutôt que json partout. C’est du json en binaire donc c’est plus léger, rapide et on peut stocker du binaire sans conversion. (et oui il existe une bibli JS) ;
  • Le support des clés publiques à 43 caractères. Je viens de découvrir ça avec horreur, certaines clés publiques (très peu) font 43 caractères plutôt que 44 ;
  • Les requêtes trop vieilles sont supprimées de la bdd.

J’ai commencé à faire des jolis schémas avec Mermaid pour la doc du protocole, est-ce que vous trouvez ça clair ? (j’ai prévu un autre schéma pour le contenu des paquets à chaque étape mais mermaid est plutôt limité en fait)

Hier soir j’ai essayé de faire un test presque grandeur nature, en faisant tourner en local 4 serveurs et en lançant 7 requêtes de mixage, mais ce cher Destin©™ était contre moi : déjà la blockchain avait du retard donc les premières transactions ont mis 3 heures à s’écrire, et en plus j’avais pris un serveur BMA qui ne stockait pas les transactions, donc forcément ça marchait pas ! Alors ça serait effectivement une bonne chose qu’on puisse savoir via l’API le store-txs d’un nœud Duniter.


#32

Hop, une nouveauté :

  • Le support d’un proxy SOCKS5, donc la possibilité de faire tourner le nœud avec un hidden service. Parfait quand on a une IP dynamique comme moi.

Voici donc mes 2 instances publiques, vraiment publiques cette fois :

4QRZj4bHpXTdJajfX8mTf2RmYQhKX7BtiMiZL3z5Lo8F svetsae7j3usrycn.onion 10951
FE4p3w7LvfDtat7pwNky5vZ9SPGKRrFid8gS2bg8Pjka svetsae7j3usrycn.onion 10952

Du coup mon serveur HTTP avec Cesium, WorldWotMap et wotmap est accessible aussi en onion sur le port 80…

Edit: Page du projet sur mon site, avec explications (si quelqu’un veut aider pour traduire en anglais…)