 and I'm stalking this team, no. All right, well thank you everybody so much for being here. I'm really excited to be a part of DEF CON this year. So I want to of course thank Nathan, Ajit and the whole team that's running the blockchain village for having me and I want to give special thanks to my friend, Ron Stoner at Forward Secrecy for encouraging me to participate and submit a talk this year. So we are going to be talking about building a microcontroller Bitcoin address generator. And what that means is building essentially a homemade hardware wallet or at least a homemade hardware wallet with some limited functionality. So first a little bit about myself. I'm a full-time software engineer at Microsoft based out of Pittsburgh. So I am working on backend and system stuff for an Azure storage product. My day job doesn't have anything to do with Bitcoin or blockchain, but I run chaintoots.com and a YouTube channel on the side. So I like to create content about explaining how cryptocurrency and blockchain systems work and what some of the use cases are. So I put up articles, videos, code projects and that sort of thing. And I really focus on kind of teaching the core concepts around blockchain systems and use cases. I don't really do any kind of like investing or money talk, but I do explain why sound money is important. So first, of course, the quick disclaimers. I am not a cryptography or security expert by profession, but I am a working software engineer and care a lot about code security and those sorts of things. Security is a complex and evolving topic, especially in the blockchain space when it comes to securing our funds and our wallets and those sorts of things. So this is really a proof of concept project and I wanted to show that it was possible and kind of enjoy the process of trying to build an open harbor open source cryptocurrency tool that I could use and share with others. So a little bit of context for the project that I actually built here and that is what's the core of crypto ownership? So if you've been around in the space, you know that the core of crypto ownership is private keys. Every Bitcoin wallet or Ethereum wallet or DigiByte wallet starts out with a seed phrase these days and that's used to generate private keys which are 256 bit numbers that are kept totally secret on the client side. So we never reveal our secret keys with anybody else. Those private keys are used to generate public keys and those public keys are then hashed and encoded and turned into our addresses. So these are the actual public facing addresses that we give to somebody else when we want them to send some funds to us. So private keys are used to prove that we own some amount of Bitcoin funds that we wanna spend by using digital signatures. Anyone with the keys can spend the funds and so it's absolutely critical when it comes to cryptocurrency that the keys are both securely generated and securely stored so that nobody else can get at them. Andreas Antonopoulos likes to say, I've heard him say, and I repeat often, not your keys, not your coins. So that's a really critical concept when it comes to any of these cryptocurrencies. One of the innovations that has come along in the space because of this security concern is hardware and other forms of offline wallets. So the commercial solutions like the Keep Key, the Trezor, the Ledger, those are examples of hardware wallets. And what those are is those are specialized devices that generates cryptocurrency private keys. They store them and generate them securely offline so they don't have to be done on a network device and they will sign transactions presented to them using a very limited protocol for communication between the hardware device and the PC that you're using to actually broadcast that transaction to the blockchain. There are also even simpler and earlier solutions like paper, metal, et cetera, wallets. So people would generate key pairs using maybe an air-gapped network or air-gapped offline computer and sent to a non-networked printer to create a paper wallet and store those key pairs so that they could load up a paper wallet with funds that they wanted to later sweep into an online wallet and spend. So in general with offline wallets, whether it's a hardware wallet or a paper style wallet, these keys are generated and stored on a device that's not connected to a network. So this is fundamentally distinct from the kind of hot wallets like full-node wallets, like a Bitcoin Core instance or mobile-like clients like you would use on a cell phone. Now, so the typical solutions for this, building a hardware wallet to keep your keys secure is a commercial device. So these are devices that are developed by a company. For example, I like the keep key which is developed by ShapeShift. There's the Trezor and the Ledger and these are devices that are ready-made that you can go out and buy. Now, almost all of these devices, as far as I'm aware, do have open-source firmware because we often like open-source to help mitigate issues of trust and backdoors in the crypto space. But I kept thinking to myself, why couldn't I build one of these myself on some cheap hardware? And thus my project, MicroBitAdder, was born out of lots of tinkering, experimentation and perhaps getting on my wife's nerves. So I thought it would be really interesting to generate real offline key pairs for cryptocurrencies using my own code that I developed myself. I had some basic experience with microcontrollers from another project that I built and presented at the blockchain training conference last year, actually where I met Ron Stoner. And this was a proof of work simulator on a little circuit playground device. So I'm not an embedded engineer by any means but I had some experience working with these little devices and just found them to be really fascinating. And I wanted to see if I could build something like this, a tool for generating key pairs on readily available, fairly straightforward to code products. There's a couple major challenges with this idea though. First, I needed a platform with enough memory and computing power to store and run code to do these cryptographic computations. The M0 platform, which is that little circuit playground device that I showed in the last slide was way too insufficient for being able to do SHA and ECDSA and store all of that code on the flash memory available on that device. The next major concern was cryptographic primitives. So to do Bitcoin address computation, I needed SHA-256, write MD-160. In order to support Ethereum, I needed Kekak SHA-3 and I needed the appropriate elliptic curve algorithm used for the public key cryptography. And the final very important requirement is it has to have a cryptographically secure random number generator. So I have to have some way to get true randomness, not pseudo randomness to generate keys. So how did I work through these particular challenges in picking a simple hardware platform? For the memory and power needs, I decided on the Adafruit M4 platforms. So they have several different devices, such as the ITSI-BITSI M4 and the Grand Central M4, which are the ones that I use to develop and test this particular project. It runs on an Atmel, a SAMD51 processor. Across the devices, both have at least 256 kilobytes of flash memory and 192 kilobytes or greater of RAM. So they had plenty of juice to load some cryptographic code and be able to do these computations quickly. Now, how do I get cryptographic primitives? I think most of us in this space know kind of the number one rule is don't roll your own crypto. I'm definitely not a cryptographer and don't have quite the math knowledge to implement my own crypto. So I needed to get trusted secure crypto primitives that would run on these little platforms that don't have an operating system. Standalone Python libraries are fairly hard to find and run on the microcontroller platform due to the space concerns. On the other hand, what I stumbled on is that the Trezor commercial hardware wallet firmware is open source and very standalone C code. Most of these individual modules that I needed to run to get this project to work were standalone and didn't tie in other C libraries. And so what I did was I ended up porting some of Trezor's open source code that was licensed compatible with what I wanted to release as and I'll go into a little more detail on how I did that later on. Now, the final very important concern was the need for true cryptographically secure random number generation. And luckily the platform choice fixed this for me. The M4 microcontrollers that I used, the entire family of them from Adafruit come built in with a true random number generator. If this was a limitation, but the platform was suitable otherwise, there are other options for getting some cryptographically suitable randomness. I could have done something like use an accelerometer or other device to get the appropriate amount of environmental noise. But having this built in made life a little bit easier. So putting it all together, how did I build this standalone address generator project? The stack starts on the bottom with a custom circuit Python module written in C. So I am actually mostly a Python developer. I do have C and C++ knowledge, but I do a lot of my work at my day job and a lot of the stuff I do for chain tutorials in Python because of the ease of development and comfort that I have with it. It's a very powerful and robust language, even if it's not necessarily powerful in the sense of getting most speed out of it. So I wanted to build the application layer for this in Circuit Python, which is designed specifically for these small devices. And I found that it was possible to extend Circuit Python to build a custom C module where I would do all of the cryptography work. The device itself is one of these M4 family devices from Adafruit, so the Grand Central or the Itzy Bitsy with an I2C character LCD screen or a receipt printer hooked up to it. And ultimately at the time of doing this presentation, I support Bitcoin, Bitcoin Cash with Cash Adder, Ethereum, Litecoin and Digivite addresses that you can generate with this. This was I think the most interesting and fun part of this project was building a custom Circuit Python module. I followed a tutorial called Extending Circuit Python by Dave Astels that's available on the Adafruit Learn website. And so I went through that tutorial and just learned the basics of creating a custom module for the Circuit Python build. This is where all the cryptography happens thanks to the Trezor code. So I get a true random number generator seed passed in from the Python layer because it's easy to use os.urandom to get your seed from Circuit Python directly. I then hash that seed into a private key, generate the associated public key and return an encoded key pair from this layer. So this is using chain appropriate address encoding. It's base 58 addresses for Bitcoin, Litecoin and Digivites, Cash Adder for Bitcoin Cash and of course, Hexadecimal for Ethereum. And as well, this custom module function returns the width or hex encoded private key depending on the chain as well. So this of course required actually building the custom Circuit Python module. I had to run the make file that's provided by the Circuit Python code, make sure all the files were in the appropriate places and this ultimately gives you a UF2 firmware that you can drag onto your microcontroller device and it will reboot with that new firmware. So since I was actually essentially building the platform that the device runs on from scratch, it required a little bit more work than the basic sort of Circuit Python functionality where you just have to edit a Python file. This required me getting down into the firmware layer a little bit. It definitely presented some challenges but luckily the folks over at Adafruit and the folks that work on Circuit Python are really helpful about getting you up and running if you talk to them on GitHub or somewhere else and have questions. I personally found for whatever it's worth that I was able to get this build running most easily on Linux. It is possible to build Circuit Python on Windows and Mac I do believe but I just worked on Ubuntu when I was working on the core of this project. Now within this custom Circuit Python module, since all of the Trezor crypto primitive code are pretty standalone, it also made it possible to do testing for this on a command line interface. So every time I wanted to go in and work on some of the important cryptography stuff and make sure that I was getting correct addresses and correct encoding, I didn't have to worry about rebooting the firmware, reloading the firmware, making sure my LCD screen was hooked up correctly and all of those little challenges that you run into when you're developing on hardware devices. So for example, on this slide here is an example of just running a test driver to generate a new DigiBite address right on the command line with a private key. Since everyone at Defcon gets to see this key pair, I would say don't take that and send any of your precious DigiBite to it but I think you all know that. Now for the Circuit Python layer, all this layer does is it's kind of the application layer that's built on top of the lower level crypto stuff which is done in C. This generates the entropy. So I'm using pythons os.urandom function which is tied right into the CSRNG built into the platform. I call that custom module code. The function call takes that randomness seed as an argument and I get a tuple back so I get the private key and the address back already encoded in the correct format. And then this code uses the appropriate libraries to display that final address and private key on an LCD screen. I also tested as well with a receipt printer which I thought was kind of fun. It's not the most robust way to store your cryptographic key data long term but I could press a button to generate a new Bitcoin address and have it printed right out for me and I just thought that was pretty cool. But I primarily tested with an LCD screen which simply rotates between displaying the address and the private key about every 30 seconds or so. All you have to do here and one of the reasons I picked CircuitPython even for an embedded and microcontroller project is with CircuitPython when you connect the device to your development PC you'll simply see a drive called CircuitPyMount to that computer and you simply edit the main code.py file and this is where all of that application layer code went and when you restart the device it will automatically run that code.py file. If this iteration of this project the usage is really straightforward and simple then and comes with some pitfalls that I'll talk about next but each reset of the device will just generate you a new completely random key pair that you can copy down. So this is what the final project looks like wired up in a couple different ways. Generating Bitcoin addresses with a little itsy bitsy on the screen with the larger Grand Central and also showing it generating key pairs and printing to a receipt printer. So this was a really interesting project. I had a lot of fun building it and I was really, really pleased with the results and the fact that I was able to get a real working Bitcoin address generator running. That said, there's a lot of potential pitfalls when you're working with cryptography and I wanted to talk about some of those issues as part of this talk because I don't want everybody to think that this is something that you can just take and run with if it's guaranteed to be secure and more so what are some of the things that you can run into if you're choosing to tinker with a project like this on your own. The first and perhaps most obvious pitfalls are cryptography foot guns. Again, I'm not a crypto expert and there's always hidden dangers with implementations. I tried to mitigate those as much as possible by using trusted primitives. So I used libraries for the Trezor hardware device which is a very, very popular crypto hardware wallet. The Trezor team works really hard to take in bug reports. I'm sure has people that are cryptography experts working on the code and I felt fairly confident using these and was able to I think go forward assuming that shot 256 was gonna work correctly if I use their code. I also kept things simple. For this at least first round of this project, all it does is generate a key pair. It generates a random private key and then walks through the steps to get a pub key and finally an encoded usable address. I don't have any extended support for many of the features that we've come to enjoy like HD wallets and those sorts of things and I'll get to that in a bit as well. And then finally tested, tested, tested manually against known working implementations of key generators. So I would use some different places where I would use my device to generate completely throw away private keys. I would plug that into a paper wallet tool for example and make sure that I kept getting the correct public address because the last thing that I would wanna do is send funds to an address and have it turn out that the address was wrong based on the private key and then lose those funds forever. Major pitfall that many of you may have been thinking of while listening to this right now is that single key pairs are simply way out of favor and considered a legacy way of dealing with private key data. You have to make sure that if you're generating a single key pair for fund storage that you copy it correctly and double triple check before you send any funds to it because base 58 like is used in Bitcoin addresses and in the with private key format is not the most human friendly format. It's a little bit more compact than hex but it's also super easy to screw up was that a capital or a lowercase W that I wanted and that was something that I ran into when I was actually testing this stuff with some live funds. The encoding's just not human friendly and it is easily corrupted. Bad handwriting, character distinctions like lowercase uppercase, potential for water damage if you're on paper. These are all huge problems for long-term key storage that are important to consider. And as is, the code that I generated only shows this key pair once. So you had to be really careful to copy down everything and then if you were gonna reset the device you had no way of verifying the key pair you copied down was correct again. So let's talk about the fun stuff which is potential future improvements. How can we make a project like this that's a tinkerers homemade offline wallet better, safer, more secure? I think the first and best thing that I could have done to make this better and would like to consider as I maybe iterate on this project in the future is upgrade to BIP39, BIP44 compatible seed phrases instead of single key pairs. So instead of directly generating a private key from the true random number generator generate a seed phrase and encode it as a mnemonic using the BIP39 standard. This is much, much, much better for reasons that a lot of us in the crypto space are fairly familiar with. You have a backup that's much more human readable. A backup that is much easier to fix if you do get a little bit of water damage or something like that or dealing with bad handwriting. It's much easier to figure out what an English word might be if a character or two is off than in a string of seemingly random information like a with encoded private key. We could then generate new addresses as needed or even if we wanted to keep it simple and just grab the first address from the tree. This is still a much safer and easier backup solution even for a single address usage of this type of device. Now I will say of course again another thing that's fallen out of favor is address reuse in general for privacy concerns. So it would be best if we're using a BIP44 standard in an implementation of this in the future that it would allow you to generate new addresses from the given seed but as well even if it was just used to generate the first key pair if you have a mnemonic backup it's gonna be much safer for the users. Several UI UX improvements that could be made, warnings about some of the things that I talked about like, hey, don't lose this, make sure that your seed or make sure that your key is copied down correctly. Maybe in fact it should actually store the key pairs for a while since it's designed to be a standalone offline never connected to a network device. It could be feasible that you would wanna keep maybe an encrypted copy of the seed phrase on there or a list of the generated key pairs on there in case the user screws up and wants to go back and make sure they copied something correctly. This was built on CircuitPython 4 which has now been superseded by CircuitPython 5. So it would of course be wise to upgrade my custom module custom firmware to the latest builds for supportability. Downside the build process was tricky. It was probably the hardest part of getting this up and running. Question could be a potential improvement. Is this device powerful enough for a pure Python implementation? I originally got the idea of doing the lower level cryptography in C and then having a CircuitPython application layer because I was dealing with the particularly limited devices I was trying to do this on first before I moved to the M4 platform. I haven't really tested out whether or not the M4 is powerful enough to load pure Python implementations of the cryptography and therefore have a pure Python project. I would like to do that for easier development and less complexity for both myself and potential users of a project like this. The downside is of course with anything cryptography making sure that the crypto primitive libraries that I'm using are up to snuff in terms of their security. And as far as I understand it, there can be some more concerns with doing crypto in a Python environment versus a C environment with like side channels and those sorts of things. I would love to consider doing more unit testing. It's always a good idea to catch basic cases and edge cases through a unit test instead of manual testing. So anytime I make some kind of change to the code I could have test cases that would check and make sure that key pairs are being generated correctly. A lot of the Bitcoin BIPs that are involved with these sort of wallet generation actions do have some test vectors that I could put into a unit test and make sure that I'm not missing strange edge cases. And I'm just open to ideas. I build projects like this outside of work just as something that I enjoy. I like to tinker. I like to learn about Bitcoin and crypto tech and then teach other people about it. So I'm always looking for ideas and perhaps something new will pop into my head tomorrow about how I could work on a project like this and make it better. And that's all I had for the main presentation. I would love to take any questions you all have. If I'm not mistaken, I do believe that the Grand Central M4, which is one of the devices that I worked on, it might have some kind of key store capability but I can't say for sure on that. Yeah, that definitely would be nice and that would be something to investigate as well as part of potential future improvements and tinkering with the idea. I think at the very least, if I could get it to generate a seed phrase instead of just a raw width and address key pair, it would certainly make backup safer even if it doesn't store them on the device because that way at the very least, you can make sure that you're writing it down correctly and backing it up. It's obviously not a full hardware wallet implementation. It doesn't sign transactions or offer modern trees of addresses. It was kind of a proof of concept for the initial idea of can I generate a basic, basic crypto wallet with a little microcontroller, like something that's simpler even than a Raspberry Pi and I'm glad I tinkered with it and it worked out.