Click here to Skip to main content
15,849,262 members
Articles / Security / Blockchain

NBitcoin : Cryptography Part 2

Rate me:
Please Sign up or sign in to vote.
4.94/5 (22 votes)
21 May 2014CC (ASA 3U)6 min read 59.7K   25   10
Two Factor keys and Stealth Addresses
Image 1


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 Clignement d'œil)

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(); //Create a new key
BitcoinSecret secret = key.GetBitcoinSecret(Network.Main);
Console.WriteLine(secret); //Will print the key in base58 check format
BitcoinEncryptedSecret encrypted = secret.Encrypt("This is my secret password");
Console.WriteLine(encrypted); //Will print the encrypted key in base58 check format
key = encrypted.GetKey("This is my secret password"); //Get the same key as before

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)


In code:

BitcoinPassphraseCode result = new BitcoinPassphraseCode("This is my secret password", Network.Main, null); //Generate a passphrase, even if the password is used in the constructor, it is not embedded in the PassphraseCode
Console.WriteLine(result); //Print passphraseCode in base 58 check format
//Give the passphrase code to the third party.
var generationResult = result.GenerateEncryptedSecret(); //Generate a new encrypted key
Console.WriteLine(generationResult.GeneratedAddress); //Print the generated address
Console.WriteLine(generationResult.EncryptedKey); //Print the BitcoinEncryptedKey
//...Give the generated address back to the owner
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);
//The receiver publish the address on a forum or whatever....
//Sender then create payment
Key ephem = new Key(); //Optional, CreatePayment create one if not specified
StealthPayment payment = address.CreatePayment(ephem);
//In you want to include the payment to a transaction
Transaction tx = new Transaction();
//Receiver receive the payment via the block chain with (address.Bitfield.GetPayments(tx))
Key key = spend.Uncover(scan,payment.Metadata.EphemKey);
//Or, if you just want the public key (equals to key.PubKey)
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 :
Command line utility :
Early bitcoin page about the idea :


This article, along with any associated source code and files, is licensed under The Creative Commons Attribution-Share Alike 3.0 Unported License

Written By
Software Developer Freelance
France France
I am currently the CTO of Metaco, we are leveraging the Bitcoin Blockchain for delivering financial services.

I also developed a tool to make IaaS on Azure more easy to use IaaS Management Studio.

If you want to contact me, go this way Smile | :)

Comments and Discussions

QuestionWallet.dat questions Pin
Djenny Floro12-Oct-17 23:57
Djenny Floro12-Oct-17 23:57 
Questioncan this port to .net core? Pin
orlandocanada31-Aug-17 9:24
orlandocanada31-Aug-17 9:24 
QuestionGreat article! Does anyone have an example of using this code for a simple send/receive transaction? Pin
cloverme117-Aug-14 16:25
cloverme117-Aug-14 16:25 
AnswerRe: Great article! Does anyone have an example of using this code for a simple send/receive transaction? Pin
Nicolas Dorier17-Aug-14 23:18
professionalNicolas Dorier17-Aug-14 23:18 
AnswerRe: Great article! Does anyone have an example of using this code for a simple send/receive transaction? Pin
Nicolas Dorier21-Aug-14 2:02
professionalNicolas Dorier21-Aug-14 2:02 
GeneralMy vote of 5 Pin
Prasad Khandekar21-May-14 1:54
professionalPrasad Khandekar21-May-14 1:54 
GeneralMy vote of 5 Pin
Volynsky Alex20-May-14 14:24
professionalVolynsky Alex20-May-14 14:24 
GeneralRe: My vote of 5 Pin
Nicolas Dorier20-May-14 14:28
professionalNicolas Dorier20-May-14 14:28 
GeneralRe: My vote of 5 Pin
Volynsky Alex20-May-14 14:31
professionalVolynsky Alex20-May-14 14:31 
GeneralThank you Pin
Emre Ataseven19-May-14 10:52
professionalEmre Ataseven19-May-14 10:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.