A few years ago, I attempted to write wallet library, that was my first, learning Bitcoin project, called HiddenBitcoin. While I was not able to give out a stable release, I reused and polished a lot of the code I wrote there over the years. HBitcoin can be thought of as its successor, but while my motivation for
HiddenBitcoin was to learn, my motivation for
HBitcoin came from a need. I kept reusing my code within different
Bitcoin projects. It got to the point that the main class I'll present to you here at some point had 6 different versions. Therefore, it was time to get things right once and for all and package them into a
Bitcoin library I can use any time through a simple NuGet package.
The HBitcoin library is written on top of NBitcoin. Imagine
HBitcoin as somewhere in between
Blockchain.info's API. It gives you more flexibility, than the latter, but less than the former. To gain a real deep knowledge on
Bitcoin, you will want to check out the The C# Bitcoin Book.
By the end of this three part tutorial, you will be able to build a
While programming to an API can assist in getting an application up quickly, the developer is limited to innovations that can take place against the API.
Bitcoin Core developer and creator of
NBitcoin, the C#
Keep this quote in mind while using my library.
What Does A Bitcoin Wallet Do?
Bitcoin wallet have three key functions:
- Securely stores keys and manages the access to them
- Monitors the transactions regarding these keys
- Builds transactions and broadcasts them to the network
How to Store the Keys?
Bitcoin Addresses, Private Keys
You are probably familiar with
Bitcoin addresses, where you can send
bitcoins and know that with the corresponding private keys, you can spend your funds.
You might be also familiar with
Bitcoin wallets and know that they are generating different change addresses for different transactions. You might ask why they do not use only one
Bitcoin address? For privacy reasons. The
Bitcoin blockchain is a public ledger, so anyone can easily see what comes in and out of an address. Therefore, it is a better idea to avoid address reuse, although that does not completely solve the privacy problem, it definitely improves it.
Now we have a different problem, how can we manage so many keys? Store, monitor and spend them?
Note that the introduction of multiple keys has greatly elevated the complexity of our wallet.
Luckily, the HD wallet structure enables us to store only one key and derive the others from it. To keep ourselves consistent to
NBitcoin's terminology, we'll call it `
Bitcoin Improvement Proposals Regarding Key Management
There are four BIPs our concern here. BIP32, BIP38, BIP43, BIP44. For simplicity, I'd like you to think of BIP32 and BIP38 as the same BIPs. They are defining low level stuff, like how to derive and encrypt keys. These are implemented by
NBitcoin. BIP43 and BIP44 are built upon BIP32-38 and define more of a structure on how the keys should be organized and used. BIP43-44 is implemented by a few wallets. I started to implement them myself, but shortly I decided against them, because they would not only greatly overcomplicate the usage of my objects, but also I was not able to incorporate in them some of the edge cases I am planning to work on in the future. This way, I can present a simpler interface.
Talk is Cheap, Guide Me Through the Code!
- Start a new .NET Core project
- Add the
HBitcoin NuGet package
var network = Network.Main;
var password = "password";
Safe safe = Safe.Create(out mnemonic, password, @"Wallets\Wallet.json", network);
Safe recoveredSafe = Safe.Recover(mnemonic, password, @"Wallets\SameWallet.json", network);
Safe loadedSafe = Safe.Load(password, @"Wallets\hiddenWallet.hid");
if (network != loadedSafe.Network)
throw new Exception("Wrong network");
for (var i = 0; i < 10; i++)
How Can I Hack the Wallet?
You just have to get the (
password AND the
mnemonic) OR (the
password AND the wallet file.)
Then, you can just call Recover of Load.
Who knows the
password? The user.
Who knows the
mnemonic? Ideally, it is stored in the user's home written in some paper as a backup.
Who knows the wallet file? Ideally, it is stored on the user's hard drive.
Usually, it is enough to recover another wallet solely with the mnemonic. I don't find that to be a good approach, therefore this wallet doesn't work like that.
var safe2 = Safe.Recover(mnemonic, password, "Wallet.json", network,
When you create a wallet, it automatically saves its creation time, too, which will come in very handy on writing some SPV wallet. Therefore, when you recover the wallet, you can also feed it with a creation time, if you don't, it'll default to the earliest creation time possible, which is hardcoded:
public static DateTimeOffset EarliestPossibleCreationTime
This is the date when I first introduced the concept of creation time. Not if you'd try to recover it with an earlier creation time, it'll use the
SafeAccounts and HdPathType
var alice = new SafeAccount(id: 2);
safe.GetAddress(index: 1, hdPathType: HdPathType.Receive, account: alice);
safe.GetPrivateKey(index: 1, hdPathType: HdPathType.Receive, account: alice);
You can create accounts if you want. In the above code, I created Alice's account with the id=2 and retrieved some keys of her.
You can also notice I specified the
receive. This is the default
HdPathType, if you don't specify anything. Note some terminology uses the words "
external" and "
internal" for receive and change addresses. It becomes important later when you are receiving and spending your funds of your wallet. Always receive funds to
HdPathType.Receive and when you spend those funds, always receive the change back to
HdPathType.Change. This adds a little more privacy to your wallet. The alternative would be when you spend a receive address you get back the change to the same address. I certainly advise against that.
I would advise against implementing your own key storage scheme, except if you really know what you are doing. If for some reason my Safe is not flexible enough for your needs, open an issue on GitHub and I'll see what I can do about it.
If you liked this tutorial and would like to see more, throw me a pizza: 1LYLuYMXkCXDxSfsNoDp8FCb2mA36r29u7.
If you did not like my tutorial, then by reading this line, you accept to perform a Cersei Lannister walk of shame.
Moreover after your death, I will be entitled to take away your soul.
- Adjust the
HiddenBitcoin tutorial to its successor: