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

silkaj
python
duniterpy

#1

Voici une proposition de protocole pour un réseau de mixeurs de cryptomonnaie sûr et anonyme. J’ai déjà décrit le projet dans le forum monnaie-libre mais ici c’est plus approprié.

C’est vincentux qui m’a donné l’idée, avec son ĞMix manuel. Seulement il a deux inconvénients :

  • le responsable du service centralise l’anonymat, il faut lui faire confiance ;
  • ça lui demande beaucoup de temps, ce n’est pas possible si la fréquence des transactions est élevée.

J’ai donc commencé à implémenter un mixeur en Python. Pour assurer l’anonymat, le réseau fonctionne en oignons, comme Tor. Avant d’envoyer la transaction, qui passera d’un nœud à l’autre jusqu’au compte du destinataire, il faut envoyer une requête au premier nœud qui la passera au suivant et ainsi de suite. Aucun nœud ne connaît l’ensemble de la chaîne.

Il y a également un système qui permet d’éviter qu’un nœud vole de l’argent en le transférant sur un compte à lui plutôt que sur le compte du destinataire. (pas encore implémenté)

Trucs qui fonctionnent déjà :

  • interface JSON par HTTP, avec commandes de base
  • découverte des nœuds du réseau et actualisation de la liste des pairs
  • communication en oignon

Trucs pas encore implémentés ou faits :

  • gestion des transactions (vérification, émission)
  • antivol
  • un schéma pour expliquer plus clairement le protocole

Vous pourrez peut-être m’aider @vtexier ou @moul :
J’ai besoin de vérifier si une clé publique a reçu ou non une transaction provenant d’une certaine clé publique, avec un certain commentaire et un certain montant. Je dois aussi émettre une transaction d’un montant donné avec un commentaire.
J’ai regardé l’exemple de duniterpy pour émettre une transaction. On a juste accès à la liste des sources, mais comment envoyer x Ğ1 ? Et il n’y a pas les commentaires.
J’ai pensé à utiliser Silkaj comme bibliothèque parce qu’il y a déjà une fonction send_transaction, mais apparemment il n’est pas prévu pour, en plus il faut utiliser le “contexte” et je ne vois pas tellement comment ça fonctionne.
Merci !


#2

Chouette ! Un nouveau client en Python qui peut utiliser Duniterpy. :grin:

Normalement on peut tout faire avec Duniterpy (puisque Sakia s’en sert).

Je vais regarder comment envoyer x Ḡ1 et t’envoyer un exemple, asap…


#3

Bon ben désolé de botter en touche, mais ce n’est pas trivial en fait et c’est pourquoi l’exemple de Duniterpy est très simpliste…

Il faut lister les sources nécessaires à la somme envoyée et harmoniser le amount_base !

Je te redirige sur le code de Sakia qui est velu, mais qui gère pas mal de cas de figure :

Attention, il utilise l’ancienne version de Duniterpy, donc des adaptations sont à faire pour l’envoi par l’api du document.

Sinon, c’est pas pour balancer, mais @moul le fait dans Silkaj… :wink:
Ne dis pas que c’est moi qui te l’ai dit !

N’hésites pas à poser des questions sur le code de Sakia, @inso pourra te répondre.
Mais non je balance pas, j’informe !


#4

Merci, je vais regarder tout ça.


#5

Ce qui serait cool ça serait d’externaliser ce code dans une lib… Genre dans duniterpy ^^


#6

@Inso J’ai installé sakia depuis pip (0.32.10) et après depuis le code source (0.33.0), dans les deux cas la version indiquée dans le code était 0.32.10, et lors de l’import d’un module dans Python :

Traceback (most recent call last):
File “”, line 1, in
File “/usr/lib/python3.7/site-packages/sakia/services/init.py”, line 1, in
from .network import NetworkService
File “/usr/lib/python3.7/site-packages/sakia/services/network.py”, line 9, in
from sakia.data.connectors import NodeConnector
File “/usr/lib/python3.7/site-packages/sakia/data/connectors/init.py”, line 1, in
from .node import NodeConnector
File “/usr/lib/python3.7/site-packages/sakia/data/connectors/node.py”, line 13, in
from duniterpy.documents import BlockUID, MalformedDocumentError, BMAEndpoint
ImportError: cannot import name ‘BMAEndpoint’ from ‘duniterpy.documents’ (/usr/lib/python3.7/site-packages/duniterpy/documents/init.py)

Et en lançant la commande sakia :

ModuleNotFoundError: No module named ‘sakia.i18n_rc’

Je vais essayer de reprendre le code de la transaction pour le rendre indépendant de sakia, mais ça a l’air compliqué…

Sinon pour vérifier l’existence d’une transaction j’ai trouvé la fonction tx.times de duniterpy. Pour trouver le montant reçu par une clé A il faut bien prendre l’output contenant “SIG(A)” ?


#7

Il faut que tu lises les instructions de build dans le README.


#8

J’ai suivi les instructions pour wheel, avec gen_resources.py et gen_translations.py pourtant.


#9

Ils ont du échouer… Tu peux me montrer les logs?


#10

sudo python gen_resources.py

/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/preferences.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/preferences_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/sub/user_information/user_information.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/sub/user_information/user_information_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/sub/transfer/transfer.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/sub/transfer/transfer_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/sub/password_input/password_input.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/sub/password_input/password_input_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/sub/certification/certification.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/sub/certification/certification_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/sub/search_user/search_user.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/sub/search_user/search_user_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/widgets/toast.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/widgets/toast_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/dialogs/plugins_manager/plugins_manager.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/dialogs/plugins_manager/plugins_manager_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/dialogs/connection_cfg/congratulation.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/dialogs/connection_cfg/congratulation_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/dialogs/connection_cfg/connection_cfg.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/dialogs/connection_cfg/connection_cfg_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/dialogs/revocation/revocation.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/dialogs/revocation/revocation_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/dialogs/contact/contact.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/dialogs/contact/contact_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/main_window/mainwindow.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/main_window/mainwindow_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/main_window/toolbar/about_wot.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/main_window/toolbar/about_wot_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/main_window/toolbar/about.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/main_window/toolbar/about_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/main_window/toolbar/toolbar.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/main_window/toolbar/toolbar_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/main_window/toolbar/about_money.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/main_window/toolbar/about_money_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/navigation/navigation.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/navigation/navigation_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/navigation/graphs/wot/wot_tab.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/navigation/graphs/wot/wot_tab_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/navigation/identity/identity.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/navigation/identity/identity_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/navigation/homescreen/homescreen.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/navigation/homescreen/homescreen_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/navigation/txhistory/txhistory.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/navigation/txhistory/txhistory_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/navigation/network/network.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/navigation/network/network_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/navigation/identities/identities.ui >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/gui/navigation/identities/identities_uic.py
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/icons/sakia.icons.qrc >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/icons_rc.py

sudo python gen_translations.py

/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/ru.ts
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/fr.ts
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/de.ts
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/it.ts
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/cs.ts
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/pl.ts
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/es.ts
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/pt.ts
Updating ‘/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/ru.qm’…
Generated 55 translation(s) (7 finished and 48 unfinished)
Ignored 165 untranslated source text(s)
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/ru.ts >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/ru.qm
Updating ‘/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/fr.qm’…
Generated 123 translation(s) (40 finished and 83 unfinished)
Ignored 97 untranslated source text(s)
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/fr.ts >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/fr.qm
Updating ‘/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/de.qm’…
Generated 99 translation(s) (22 finished and 77 unfinished)
Ignored 121 untranslated source text(s)
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/de.ts >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/de.qm
Updating ‘/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/it.qm’…
Generated 104 translation(s) (29 finished and 75 unfinished)
Ignored 116 untranslated source text(s)
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/it.ts >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/it.qm
Updating ‘/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/cs.qm’…
Generated 123 translation(s) (40 finished and 83 unfinished)
Ignored 97 untranslated source text(s)
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/cs.ts >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/cs.qm
Updating ‘/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/pl.qm’…
Generated 77 translation(s) (15 finished and 62 unfinished)
Ignored 143 untranslated source text(s)
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/pl.ts >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/pl.qm
Updating ‘/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/es.qm’…
Generated 97 translation(s) (27 finished and 70 unfinished)
Ignored 123 untranslated source text(s)
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/es.ts >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/es.qm
Updating ‘/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/pt.qm’…
Generated 105 translation(s) (23 finished and 82 unfinished)
Ignored 115 untranslated source text(s)
/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/ts/pt.ts >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/qm/pt.qm


qm/ru.qm
qm/fr.qm
qm/de.qm
qm/it.qm
qm/cs.qm
qm/pl.qm
qm/es.qm
qm/pt.qm

/home/tuxmain/Téléchargements/sakia-0.33.0rc7/res/i18n/langs-1552476852.qrc >> /home/tuxmain/Téléchargements/sakia-0.33.0rc7/src/sakia/i18n_rc.py


#11

Et bien tout à l’air de bien se passer pourtant, le fichier i18n_rc est bien généré… Il est bien installé dans le wheel ?


#12

Il est dans ./build/lib/sakia/i18n_rc.py et dans ./src/sakia/i18n_rc.py mais je ne le vois pas dans site-packages/sakia.

Je l’ai copié à la main et ça a l’air d’aller. Après il ne trouve pas root_servers.yml, g1_licence.html, alors je les copie aussi.

Maintenant c’est bon, mais ça fait la même erreur qu’avant :

File “/usr/lib/python3.7/site-packages/sakia/data/connectors/node.py”, line 13, in
from duniterpy.documents import BlockUID, MalformedDocumentError, BMAEndpoint
ImportError: cannot import name ‘BMAEndpoint’ from ‘duniterpy.documents’


#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 !