After my first article on NBitcoin, I decided to make a serie of article on NBitcoin, the bitcoin gateway for .NET Developers.
This article will skip the internal math so you can get the general idea and data flow. I will briefly point to link that can explain the math better than me at the end of this article.
My first article was discussing about some basics of how Bitcoin works to ensure you can spend the funds you claim to own.
This article will speak about some solutions to increase privacy and security.
For privacy, the root of the problem is that bitcoin transactions are publicly published. So if you use always the same address, someone can see how much you have and receive and the timestamps, and deduce information about you.
Snowden’s leaks, switched on the “privacy by default” light in the head of lots of people. Not a bad thing, since such behavior will protect against other treats as well.
We explored one solution in the previous article called HD Wallet. This works fine, but if a root public key leaks with the IDs you used to derive children keys, then you are exposed again.
We will explore Stealth Address, that protect against such problem.
We will also see how to encrypt your keys with a password, we call such keys Encrypted Key.
And, in the same way as HD Wallet from the previous article, we will see it is possible to give right to a third party to generate an Encrypted Key for you without giving him knowledge of your password, nor the underlying private key.
If this third party is your own payment server, it means that if it is hacked, there will be no access granted to your private keys, making hacking futile. (but you stay weak to physical and personal treat )
Encrypting keys : Two factor (BIP 38)
There is two ways to encrypt a key :
- By knowing the key,
- By knowing the PassphraseCode (useful if you delegate the process to untrusted third party)
Encrypt by knowing your key
Imagine that you own a key in Bitcoin to reclaim your funds.
Normally, whoever possess the key, possess the right to spend your fund, this is fundamentally one factor.
But you can encrypt it with a password, so someone need both : your key and know the password to spend your funds.
In code :
Key key = new Key();
BitcoinSecret secret = key.GetBitcoinSecret(Network.Main);
BitcoinEncryptedSecret encrypted = secret.Encrypt("This is my secret password");
key = encrypted.GetKey("This is my secret password");
The encryption process is defined by BIP 38. It is protected from brute force by the key derivation algorithm Scrypt, which will slow any attempt.
Encrypt by knowing the PassphraseCode
In some case, you want to allow a third party (a payment server for example) to generate bitcoin addresses and the associated encrypted keys for you… but without giving him neither the key or the password.
In such situation, you need to give a PassphraseCode to the third party, the third party will then generate keys for you. (For each business transaction for example)
BitcoinPassphraseCode result = new BitcoinPassphraseCode("This is my secret password", Network.Main, null);
var generationResult = result.GenerateEncryptedSecret();
Key key = generationResult.EncryptedKey.GetKey("This is my secret password");
BitcoinPassphraseCode is the only information given to the third party, and does not include any sensitive data. The third party can then use it to generate encrypt keys for you, but can’t decrypt them.
Protecting your privacy : Stealth Address
If you want this simplicity of a static, fixed, bitcoin address but with the privacy that an BitcoinPassphraseCode or HD key can give you, then stealth address is for you.
Here was the original idea behind Stealth Address:
As a receiver, you will publish a spending PubKey and keep secret the associated spending Key.
As a sender, you combine the spending PubKey, with an ephemere, random key, called Ephem Key, that will generate a Stealth PubKey and so a Bitcoin address to which to pay.
As a receiver, you will receive the Ephem PubKey, and will combine your Spend Key to retrieve the Stealth Key to spend the funds sent to the generated Bitcoin address.
However, there is one fundamental problem with such design.
There is no automatic way to send the Ephem PubKey from sender to receiver.
The solution is to include the Ephem PubKey in the same transaction that send the funds to Bitcoin Address.
In the transaction, two TxOut will be generated : The payment to the Bitcoin Address (Spendable output) and an unspendable TxOut with the ephem key embedded in it.
We call such unspendable TxOut the Stealth Metadata. I will call such pair of TxOut a Stealth Payment.
As a receiver, you will scan all transactions with such Stealth Payment on the bitcoin network, you will extract the Ephem PubKey, then you generate the Stealth Key and checked if it’s address match the one in the spendable output.
As a receiver, you want to automate such scan, however, you don’t want to give to the scanner your Spend Key, because the scanner, or a hacker, would be able to use it to steal your money.
The solution is to introduce a Scan Key that both the scanner and the sender will use to generate and scan the Stealth PubKey.
This way, the scanner will be able to report your balance by scanning the blockchain without the need of the Spend Key.
However, now the sender need two pieces of information to pay you : The Scan PubKey + the Spend PubKey these two are bundled inside a BitcoinStealthAddress that the receiver publicly share.
Now, the sender want to send you some money, here is how he generate the Stealth PubKey. (Note that now he needs the two keys, from the StealthAddress)
As a receiver or scanner, you don’t need the Spend Key anymore to check if a transaction is for you.
And if you want to spend the money, then use the Spend Key manually to get the Stealth Key.
This is the current design of DarkWallet transactions, and the one that is expressed in the following NBitcoin code.
Key scan = new Key();
Key spend = new Key();
BitcoinStealthAddress address = spend.PukKey.CreateStealthAddress(scan.PubKey,Network.Main);
Key ephem = new Key();
StealthPayment payment = address.CreatePayment(ephem);
Transaction tx = new Transaction();
Key key = spend.Uncover(scan,payment.Metadata.EphemKey);
PubKey pubkey = spend.PubKey.UncoverReceiver(scan, payment.Metadata.EphemKey);
You can replay these steps in parallel with sx (command line utility on linux) to verify the implementation.
There is a deterministic unit test for that.
This article tried to stay developer friendly. The underlying math documentation are published in the links below. The general flow was hard to understand for me, because I am not very familiar with the underlying math (Elliptic Curve), I hope this article will help other developers to grasp the idea without being lost in the math.
Next, I will make articles on the network aspect of bitcoin.
Underlying math, and scanner : https://wiki.unsystem.net/index.php/DarkWallet/Stealth#Theory
Command line utility : http://sx.dyne.org/index.html
Early bitcoin page about the idea : https://en.bitcoin.it/wiki/Sx/Stealth