# Developer Perspective Adding Tor Support to Crypto Wlallets by Czarek || EPS 2025 Workshop

- Channel: [Ethereum Cypherpunk Congress](https://streameth.org/ethereum-cypherpunk-congress)
- Date: 2026-01-09
- Duration: 20:32
- Topics: web3, privacy, now, crypto, cryptography, blockchain, data, security, human right, rights, tech, technology, internet, open source, free, freedom, ethereum, hackers, ethics, cypherpunk, dev, developer, dapp, decentralization, bitcoin, computer, surveillance, cyber, peer2peer, p2p, love, solidity, zk, zero knowledge, education, academy, w3pn, privacy stack, devconnect, 2025, eps25, pse, privacy stewards of ehtereum, ethereum foundation, ef, Education
- Watch: https://streameth.org/watch/yt-Wn1Q5ThHISo
- YouTube: https://www.youtube.com/watch?v=Wn1Q5ThHISo

## Description

czarek (Cake Wallet) goes into talk about embedded and non embedded Tor, what are the benefits of it and  how it works for them at Cake Wallet.

Ethereum Privacy Stack is a global privacy summit during Devconnect 2025 bringing together Ethereum builders, protocol maintainers, and advocates. 
Featuring Vitalik Buterin, Roger Dingledine, Andy Guzman, Polymutex, Ameen Soleimani, and 30+ speakers on 2 stages, celebrating privacy acceleration.

Ethereum Privacy Stack: 
http://eps25.web3privacy.info

Organized by 
Web3Privacy Now & Privacy Stewards of Ethereum

Web3Privacy now collective: http://web3privacy.info
Privacy Stewards of Ethereum: https://pse.dev/

## Transcript

[applause] Thank you for the introduction. So yeah, my name is Charik. I work at Cakewallet and I'm the one who implemented embedded tour in Cake Wallet. So before we start, let's get some vocabulary straight like what is embedded to or actually let's start first what is a non-mbbedded tour because we have to get there some way. So if you go to your favorite app store or web browser and look for tour for Android you will end up with something like Orbot or Invisible Pro which is a very good software. Uh Orbot is maintained by Guardian Projects. invisible is is maintained by a different guy and they both support something like VPN mode or socks proxy in order to establish to connections. Uh there are many pros to using a non-mbbedded tour. For example, you can have more than one app use store uh a single to instance so you don't waste memory on multiple to instances on operating systems. Uh there's no need as for us developers there's no need to establish to do anything about that because user just configs that entirely out of our entirely outside of our app and everything just works for the most part at least. Uh but where can we find the embedded the different one the one that we put inside of our app? Well, uh, Orbot on Android very conveniently maintains a list of some apps that use, uh, tour. And if you read a comment here, it will say that this list is here to prevent to over to. Uh, so uh, if you go to to browser or onion share, Briar or some other apps, we will see that they are using to and they have their own binary. They are not using orbot. They have something that they ship on their own. So the vocabulary is very simple. Embedded tour is just a normal tour embedded inside of our of your app. And also before we move forward, there are a few different flavors of tour that you can get. There's tour, there's art. RT is the new rewrite of tour in Rust. It is still experimental, but it's in production in some places. Then we have Orbot invisible embedded that can run in VPN and socks mode. And then you multiply that by Android, iOS, Mac OS, and Windows and Linux. and you end up with pretty large amount of configurations to support. That's that's [snorts] a lot for developers to test and for testers too. Uh but if what I said before was true, we are all ready like we can just enable the VPN mode or users can enable the VPN mode and that lies entirely out of sight of our app require zero setup and should just work. Um but there will be some hiccups with that. For example, on-ramps and instance swaps really don't like to exit nodes because anyone can uh access them. We had a talk on permissionless before uh before that's a permissionless network. Anyone can connect to tour. Anyone can do anything with that. Uh so exit uh offramps and instance swaps don't really like that. Also some normal services that do not block to may accidentally block it by web application frameworks or just normal denial of services uh prevention systems because exit nodes share IP addresses and if you don't have a proper onion endpoint you may end up with uh a situation when your server just denies uh requests coming from the to network but everything else should work. Uh [snorts] so why should you as a developer bother with supporting tour? Well, there are a lot of things uh that come with to for example you get a explicit testing for to connectivity. You can host onion services that help circumvent censorship. You can properly handle errors from third parties and I don't mean like an actual error. I mean when cloudfare is going down and you are seeing HTML instead of JSON you get to test that because with to many things will break that send request outside just by the nature of the network. Uh we can also make man-in-the-middle attacks more difficult especially if the network stayed inside of the onion network. There's less metadata linked to the users because we don't see any IP addresses and every look uh every request looks exactly the same on our back end. Uh but why bo embedding? We can get all of those benefits by just using to in a VPN mode. Why should anyone put it inside of our app? So there are some downsides to the external to of projects such as orbot or invisible. It adds extra CPU load which on desktop platforms wouldn't be that bad but on mobile devices it may prevent the device from entering a deep sleep stage deep sleep deep sleep state uh which will drain battery because the device will have to be awake even with uh screen turned off and you cannot use it with other VPN services. So if you use Mulvat or tile scale you cannot use that with a systemwide uh toVPN. Uh so how do we design the embedded tour inside of our app? Let's take a look at Orbot. Orbot has a lot of features. It allows you to set up how you connect, what port you use, what connection, everything. It has so many options. And we take a took a good look at this at Cake and we decided to put an on and off switch that turn on and off. And that's all we support for now. Uh we think that it is enough for most users. Uh in future we do plan to maybe do future parity with orbot but more likely we end up with a way to edit to C file for the power users. Uh but like okay I see what we are doing here but what are we actually trying to solve now? Uh the most requested features that were coming to us is people were trying to host their own nodes uh and they didn't have public IP address or IPv6 wasn't really working on the mobile data. So the easiest way to do that currently is to just expose the node via onion service because it's just uh one command and two lines of config files and we are ready and also uh the some people like to say that you don't trust you verify but we would like to step take that a step further and don't trust if you don't have to. So if you don't want to trust a third party with metadata the then don't do that. uh for example if you are sending requests to many services such as like some even entirely custom such as uh services for the NFT pictures which are [snorts] can be hosted anywhere on the internet you really don't want them to know that you own that NFT and that's a metadata that you are leaking if you are not using things like to uh we also don't want to break any existing function functionality so we wouldn't like to break for example background sync that we have in cake which all If you enable it, it will check on your device if there are any new transactions coming to your address and send you notifications if they do. And we also wouldn't like to increase the difficulty of the app itself. So let's do some coding. First uh we will be using RT initially. Uh it's the Rust version of to it's experimental but it had a flatter package already made by the foundation foundation devices which are also in the crypto space and we decided to go with it because it supports all platforms. It was really good. It worked out of the box was awesome. It was multiplatform. It really saved us a lot of time but it didn't work. Uh that's the kind of issue that we hit. Uh it was work. It was good when it was working but when it was not working we had really nonreproducible issues only we couldn't connect to some nodes the or to like some protocols for example electrum wasn't working at all in cake while we could establish connections to JSON RPC of some of the Ethereum nodes but it was random one day it worked one day it didn't uh which I guess was uh caused by the fact that it's RT and not the to used by to browser the old implementation uh overall it was good there were no prebles in it there it It's very easy to implement but never got merged because it never passed the testing. Then we went ahead and tried the toroid which is maintained by guardian project. It is uh it ships a reproducible binary or library. You will see in a second uh that you can use in your app very easily. Uh they actually host their Maven repo on GitHub. So it's very easy to audit everything. You can just go there download the file and actually let's do that. Let's take a look at this. Uh if you download it and unpack the file you can see that there are there is a binary uh liptor.so and yeah uh lip.so should mean that it is a shared object. It not it's not really a shared object uh at least not as far as I'm concerned because it has an interpreter which means that you can just launch it as a command. It is not a to library. It is just a normal to that you can install on Debian or any other operating system. Let's quickly verify that claim. If I try to push that file to somewhere on my Android device and execute it as a program, we can see something that anyone who use to should be familiar with the standard notice that happens when you run the tour for the first time. So yeah, it is a normal binary. So to use it, we should be able to just do /tor uhso-c path tuto and it should be good, right? Right. &gt;&gt; Well, yes, but what happened with the iOS, Linux, Mac OS, and all the other operating systems? Well, nothing. But it was working on Android. It was working and was working very well. It made it to production uh with Android only sadly, but it was very good. So, since this path was working, it was non good, then we decided to do it again. This time for iOS, it shouldn't be that bad, right? So there's an orot apple project which is doing uh exactly the same thing as orbot android but for Apple devices and it conveniently leaves storeframework in direct dependencies in the rhyme which we decided to use. We create I I personally created a new project uh in uh flatter. I made sure that it will abstract store Android from previous steps and to framework uh in in a way in which we can use it in a platform independent API because we are in flatter we support all operating system in one codebase. So I abstracted it. I made a test request to uh check connectiv to check. Project.org it was working and then I had some other Jira tickets going on. I couldn't work on tour. So, a couple of weeks passed by and then I'm coming back to the project just to see that it's not there. Like the code that I changed, the code that I depended on just got removed. As you can see in the commit message there, there's a very sad thing that really made me very angry and very mad. Switch to pre-built XC framework because previously it was building to uh so and okay like to Android is also a pre-built. It's a reproducible pre-built. So, I'm pretty sure it's just the same thing happening here. Uh, no, it's not. It's not reproducible. It's a random uh binary downloaded from uh GitHub releases. It's not pinning by GitH. It's ping by git tax. I'm not going to rant here about that too much, but it wasn't a good fit for us. Essentially, the maintainer told me to don't verify but trust them, which is not happening. We are touching user funds. We cannot put a binary that someone else compiled in our process name space because then they could just steal the coins. We are not doing that. So that's clearly not the path. Let's rethink everything. Let's see what we need to do. So we need a tour like any kind of to preferably the one from tour browser. We need a crossplatform build system because we are a crossplatform app and we need an uh for starters Androids and Android and iOS will do. Then we would like to do Linux, Mac OS, Windows, all the other operating systems. uh we don't need a platform dependent projects. We just saw with that like it's it's breaking there. If you depend on five different projects to in your crossplatform app then you have five different issues to solve whenever something changes. So we don't want that. Uh we want a really simple solution uh ideally something that we have like one place to manage builds. We want them to be reproducible and ideally bootstraable uh as well. And we went with a system that we already have which some Bitcoin OGs may know. It's a country/ depense directory in the Bitcoin core. Uh it's deprecated. It's not there for many years now. Uh but it's still used by Monos and we support Monero so we still have it around. Uh it's very simple. Uh you just it's the perfect build system. I love it. You just make host and it it just builds uh the package definitions are very easy. Then you make a list of the packages. And actually I lied. We have a rewrite uh of that uh in go because have do you see this like this is a this is terrible. This is a macro that defines that that I we cannot debug that uh I I don't have skills for that. But we uh we have a rewrite of that happening in Go which just uses JSON which is slightly uh easier to maintain and slightly easier to lead read than nested macros in make files and okay so then we need to build lip event open SSL XZ uh to and magic secret ingredients that we will get into later and then we need to do that for Android iOS Mac OS Linux Windows and then we also need like 40 build dependencies uh because we want to bootstrap the build from source which is very difficult uh but we did that I will skip how that happened because it was really painful and very long time uh we had a fat XC framework for iOS Mac OS and all the different architectures we have for Android and we have an easy way to expand the support to Linux and Windows in future that's coming very soon and all of that is reproducible uh but do you remember this slide uh I showed you that the to liptors was a binary and not a library so how are we getting the library like an actual one uh we are actually building a static archive of flip tour. Uh I found out by reading a make file in the tour project was quite easy and then uh instead of reading documentation I just created a 100 lines of C++ wrapper that exposed the uh static archive in a shared library that we can just load. Uh there are a couple so before I go there uh so essentially instead of running a comment we just load the binary with the param. So it's pretty much the same API just slightly uh different way to call it. Uh also to API.A couldn't we could use the uh to API.A a directly but there are some quirks to that that I don't really like like iOS simulator and iOS conflicts when doing that if you don't do that fully properly and the code remains unloaded unless user starts embedded to which is really important for us because if users don't want to use store there they shouldn't have any to code in memory and also do you remember this switch on and off we actually removed half of the functionality with this update uh because it doesn't turn off uh you can't turn off uh I mean you can turn it off you can start it again if you are uh using it as a library. So we just we just don't do that. We gracefully stop using to so it's still running in the background. If there are some connections made to it, it can finish at whatever speed they want. And uh but yeah, we won't be using it for any new requests. So that's it. We have a working tour. Uh right, there's nothing else. Where's the VPN? Like I told earlier about the VPN that routes all the traffic. Like where's the VPN here? Uh well the fun is just just begins. Currently we nothing changed in our app. We just shipped a binary that library actually that we run and that that's it like it just uses some memory and some storage and it doesn't do anything. So uh how to properly route the traffic through to if you have an embedded uh if you have it embedded in the app. Well you have to start a sock proxy and then you have to route all the requests through it. So the best way to do it is plan early. Make all connections originate from a single class. have it really well prepared. But sadly, Cake Wallet is seven years old and I joined it two years ago and to was implemented a year ago. So this option is clearly a no-go for us. Uh so instead we we had a PR uh a big one I would say that changed every single place that we make a HTTP request into a proxy wrapper that then sees if we can use to or no and routes the connection through to or it doesn't. It is just a simple wrapper about standard HTTP methods some of the Dart uh IO clients that is that are also used by some libraries and it also supports a really cool thing where you can pass it and clear URI and onion URI. So if to is enabled it will prefer the onion endpoint but if it's disabled it will go to the clearet one uh without any logic in the uh in other places of the app. It just happens on the like request level. Uh then we have third party libraries. Uh but how do we tell them to respect our proxy? Like they have no idea that we run tour. Well, chase and hunt them like open mitten proxy, put it between the internet and your app, make it stuck there. Use your app and look for requests. If something looks like a to traffic, don't touch it. If something looks like a web request, go see where it's happening. uh manually try to patch it and to respect your sock proxy and repeat and repeat and repeat. We are still in progress of doing that because there are so many things that over seven years have been added to the app. So it's a really long process. Uh but yeah, that's pretty much the only way to go if you didn't plan that seven years ago. And that's it. By now we have a much better understanding of the app networking. We have a single place in theory that connects to the internet. We have an easy way to add new networks or proxies. For example, if you feel like supporting I2P, it's a matter of starting the dammon, configuring the socks proxy and that's it. Uh we can also enhance the app in future with per domain or per IP routing scheme. So if user wants to route some traffic through to they can do that and the rest can go over clear net and yeah uh also as quick bonus when I was flying here here cloudfare did a little oopsie and was offline uh and we use cloudflare in cake wallet for a first party API uh that shows prices of cryptocurrencies uh the support was flooded by it not working uh and yeah support just told users to enable to because we had it hosted on onion endpoint which doesn't go through cloudflare So when people enabled built-in tour, it was just working because it wasn't affected by it. So it was pretty cool, pretty cool. Uh so a quick TLDDR of the talk. Uh use established solutions. Don't go with RT or the fancy new Rust Rewrite if there is a to binary that powers to browser tails and everything. It's probably good for your project that's probably smaller than to itself. Uh so do not use experimental software unless it's production ready. And for crossplatform projects, unify as much much code as possible. When we were going with to Android and orbit Apple, it was just a lot of extra code trying to make it work with the same API in Dart. It's it's a lot of work. I do not recommend that. That's a way that feels like a waste of waste of time now seeing how simple the API is with around 100 lines of C++ code and that's it. Uh keep things simple. uh like C AI is much better than whatever else is the native thing at this very moment. So technically we could use the native APIs but going with the simplest solution is just easier and follow standards and conventions. For example, there's sock server environment variable on Linux that isn't a standard but is pretty much a convention and it made respecting it in our proxy wrapper made to tails OS support much much better because everything was properly routing through to on tails. Uh and yeah uh thank you for attending. Uh if you have any questions about to uh feel free to catch me here or email me, add me your Twitter or check the uh to implementations that you have in cake wallet at the github uri. So thank you.
