diff --git a/bitcoin_transfer/README.md b/bitcoin_transfer/README.md index 7d0b8a1..8276a92 100644 --- a/bitcoin_transfer/README.md +++ b/bitcoin_transfer/README.md @@ -1,3 +1,3 @@ -# Bitcoin transfer {#bitcoin-transfer} -In Bitcoin, everything is designed to make sure that the transactions go through. In this chapter we are going to introduce the basic concepts of Bitcoin by guiding you through a creation of simple bitcoin transaction "by hand". -Later we are going to show you a higher level framework for building transactions. +# Part3. Bitcoin transfer {#bitcoin-transfer} +In Bitcoin, everything is designed to make sure that the transactions go through. In this chapter, we are going to introduce the basic concepts of Bitcoin by guiding you through a creation of simple bitcoin transaction "by hand". +Later, we are going to show you a higher level framework for building transactions. diff --git a/bitcoin_transfer/bitcoin_address.md b/bitcoin_transfer/bitcoin_address.md index 067b907..237a419 100644 --- a/bitcoin_transfer/bitcoin_address.md +++ b/bitcoin_transfer/bitcoin_address.md @@ -1,58 +1,133 @@ -## Bitcoin address {#bitcoin-address} +# Chapter1. Bitcoin address {#bitcoin-address} -You know that your **Bitcoin Address** is what you share to the world to get paid. +## Section1. Bitcoin address + +You know that your **Bitcoin address** is what you share to the world to get paid. ![](../assets/BitcoinAddress.png) -You probably know that your wallet software uses a **private key** to spend the money you received on this address. +You probably know that your wallet software uses a **private key** to spend the money you received for sending the meney to the Bitcoin address. ![](../assets/PrivateKey.png) -The keys are not stored on the network and they can be generated without access to the Internet. +The keys, a private key and a public key, are not stored on the network and they can be generated without an access to the Internet. This is how you generate a private key with NBitcoin: ```cs -Key privateKey = new Key(); // generate a random private key +//Generate a random private key. +Key privateKey = new Key(); +Console.WriteLine($"privateKey: {privateKey.ToString(Network.Main)}"); +//Output: +//L3gyRGQ8Da1mMnDFkM9sFYbTV7P8hN8vHzmkALsfkyK7Wjfby5ZB ``` -From the private key, we use a one-way cryptographic function, to generate a **public key**. +The ouput from above code is showing one generated private key. + + +And we use a one-way cryptographic function on the private key to generate a **public key**. ![](../assets/PrivKeyPubKey.png) ```cs PubKey publicKey = privateKey.PubKey; -Console.WriteLine(publicKey); // 0251036303164f6c458e9f7abecb4e55e5ce9ec2b2f1d06d633c9653a07976560c -``` +Console.WriteLine(publicKey); +//Output: +//0251036303164f6c458e9f7abecb4e55e5ce9ec2b2f1d06d633c9653a07976560c +``` + +## Section2. Dive into more details of "new Key()", a private key, a public key. + +You're probably doubtful when you see a "Key privateKey = new Key()" from above code, with saying "Should the variable name for the privateKey be named by keyObject rather than the privateKey? + +Yes, it is a key object. If you print a privateKey variable by: +```cs +Console.WriteLine(privateKey); +``` +, you'll see the output like this: +```cs +NBitcoin.Key +``` + +Moreover, you can do lots of tasks by this key object. Try to examine what you can do by this key object by using IntelliSense like this: +```cs +Console.WriteLine(privateKey.); +``` + +You're going to be more sure it's a key object once you examine a Key class because a Key class looks like an ordinary class including lots of its members. + +It's true that an object which is created by "new Key()" is a key object. + +**However, in the NBitcoin, we often use an object which is created by "new Key()" as a private key.** +When you instantiate a key object, under the hood, in the case of the NBitcoin, you simultaneously invoke a secure PRNG(Pseudo-Random Number Generator) by default to generate a random key data and store it into a key object.   + +For more details, reference a "Is it random enough?" chapter of "Key generation and encryption" part. + +As mentioned above, a key object generated in this way contains a randomly generated key data in the object. And this object is often used in generating other types of key such as a public key, BitcoinSecret(nothing but a private key represented in Base58Check binary-to-text encoding scheme allowing you to use the private key in the UI layer, and Bitcoin secret is exactly identical concept with a WIF except for its differently called name.), a ScriptPubKey and so on. + + +## Section3. Bitcoin network and Bitcoin address There are two Bitcoin **networks**: * **TestNet** is a Bitcoin network for development purposes. Bitcoins on this network worth nothing. * **MainNet** is the Bitcoin network everybody uses. -> **Note:** You can acquire testnet coins quickly by using **faucets**, just google "get testnet bitcoins". +> **Note:** You can acquire testnet coins quickly by using **faucets**. Just google "get testnet bitcoins". -You can easily get your **bitcoin address** from your public key and the **network** on which this address should be used. +You can easily get your Bitcoin address from your "public key" and the "network identifier" on which this address should be used. ![](../assets/PubKeyToAddr.png) ```cs -Console.WriteLine(publicKey.GetAddress(Network.Main)); // 1PUYsjwfNmX64wS368ZR5FMouTtUmvtmTY -Console.WriteLine(publicKey.GetAddress(Network.TestNet)); // n3zWAo2eBnxLr3ueohXnuAa8mTVBhxmPhq +Console.WriteLine(publicKey.GetAddress(Network.Main)); +//Output: +//1PUYsjwfNmX64wS368ZR5FMouTtUmvtmTY +Console.WriteLine(publicKey.GetAddress(Network.TestNet)); +//Output: +//n3zWAo2eBnxLr3ueohXnuAa8mTVBhxmPhq ``` +Note that a Bitcoin address for mainnet starts with "1", and a Bitcoin address for testnet starts with "m" or "n". + +**To be precise, a Bitcoin address is made up of a "version byte" which is different on both networks(mainnet, testnet). But this version byte identifies the network type. And a Bitcoin address is also made of your "public key’s hash bytes". Both of these bytes are concatenated and then encoded into a Base58Check encoding scheme which has an additional 4 bytes checksum data, compared to a Base58:** -**To be precise, a bitcoin address is made up of a version byte (which is different on both networks) and your public key’s hash bytes. Both of these bytes are concatenated and then encoded into a Base58Check:** +In other words, it means that a generated Bitcoin address is always in Base58Check encoding scheme.(If this is wrong, please edit it.) ![](../assets/PubKeyHashToBitcoinAddress.png) +The above illustration shows a standard way of generating a Bitcoin address by processing entire steps(Public key -> Public key hash + Network => Bitcoin address), with not using a sugar syntax for generating a Bitcoin address(Public key + Network => Bitcoin address). + ```cs var publicKeyHash = publicKey.Hash; -Console.WriteLine(publicKeyHash); // f6889b21b5540353a29ed18c45ea0031280c42cf -var mainNetAddress = publicKeyHash.GetAddress(Network.Main); -var testNetAddress = publicKeyHash.GetAddress(Network.TestNet); +Console.WriteLine(publicKeyHash); +//Output: +//f6889b21b5540353a29ed18c45ea0031280c42cf + +//Get a Bitcoin address for a mainnet by publicKeyHash and network identifier. +var bitcoinAddressForMainNet = publicKeyHash.GetAddress(Network.Main); +var bitcoinAddressForTestNet = publicKeyHash.GetAddress(Network.TestNet); + +Console.WriteLine(mainNetAddress); +//Output: +//1PUYsjwfNmX64wS368ZR5FMouTtUmvtmTY +Console.WriteLine(testNetAddress); +//Output: +//n3zWAo2eBnxLr3ueohXnuAa8mTVBhxmPhq ``` -> **Fact:** A public key hash is generated by using a SHA256 hash on the public key, then a RIPEMD160 hash on the result, using Big Endian notation. The function could look like this: RIPEMD160(SHA256(pubkey)) +> **Fact:** Internally, a **public key hash** is generated by using a SHA256 cryptographic hash function on the public key, then a RIPEMD160 cryptographic hash function on the result, using Big Endian notation. The function could look like this: RIPEMD160(SHA256(publickey)) -The Base58Check encoding has some neat features, such as checksums to prevent typos and a lack of ambiguous characters such as '0' and 'O'. -The Base58Check encoding also provides a consistent way to determine the network of a given address; preventing a wallet from sending MainNet coins to a TestNet address. +## Section4. Encoding schemes +There is a one binary-to-text encoding scheme which is called Base64. +Base64 represents binary data in an ASCII string format with 64 characters composed of A-Z, a-z, 0-9, and +(plus) ,/(slash). -```cs -Console.WriteLine(mainNetAddress); // 1PUYsjwfNmX64wS368ZR5FMouTtUmvtmTY -Console.WriteLine(testNetAddress); // n3zWAo2eBnxLr3ueohXnuAa8mTVBhxmPhq -``` +A Base58 is a modification of the Base64 which was first suggested by Satoshi Nakamoto for Bitcoin system implementation. +The Base58 uses 58 characters by eleminating 6 characters from the Base64 such as 0(zero), O(uppercase o), I(uppercase i), l(lowercase L), +(plus), and /(slash) to avoid a mistake by an ambiguity of characters. + +A Base58Check encoding scheme, a modification of the Base58, has some neat features like a checksum to prevent typos being occured aside from a lack of ambiguous characters such as '0' and 'O' from the Base58. +The Base58Check encoding scheme also provides a consistent way to determine the network type from a given address, which means that this feature prevents a wallet from sending MainNet coins to a TestNet address. + +```cs +//Get the Bitcoin address for each network type. +var bitcoinAddressForMainNet1 = privateKey.PubKey.GetAddress(Network.Main); +var bitcoinAddressForTestNet1 = privateKey.PubKey.GetAddress(Network.TestNet); + +//Get the consistent each network type from the specific Bitcoin address. +var mainNetFromBitcoinAddress = bitcoinAddressForMainNet.Network; +var testNetFromBitcoinAddress = bitcoinAddressForTestNet.Network; +``` -> **Tip:** Practicing Bitcoin Programming on MainNet makes mistakes more memorable. +> **Tip:** Practicing a Bitcoin Programming on the MainNet makes mistakes more memorable. diff --git a/bitcoin_transfer/blockchain.md b/bitcoin_transfer/blockchain.md index ad73e62..fd1ecd3 100644 --- a/bitcoin_transfer/blockchain.md +++ b/bitcoin_transfer/blockchain.md @@ -1,6 +1,89 @@ -## Blockchain {#blockchain} +# Chapter5. Blockchain {#blockchain} -You might have noticed that while we proved ownership of the spent TxOut, we have not yet proven the TxOut actually exists. This is where the main function of the Blockchain shines: +## Section1. Introducing the basic concepts and terms for the Blockchain system Part1 + +A Blockchain is composed of blocks. And each block shapes the chain by referencing the previous block. A block is composed of a block header and transaction(s). + +See the illustration depicting a block and a blockchain, drawn by Young-min Park(Youngmtool), in the following link: +https://youngmtool.gitbooks.io/csharpdotnetconceptsandillustrations/blockchain.html + +A header is composed of several data such as version(block version information.), prev_block(the hash value of the previous block, being used to reference the previous block.), merkle_root(the reference to a merkle tree collection which is a hash of all transactions related to this block.), timestamp(a timestamp recording when this block was created.), bits(the calculated difficulty target being used for this block.), nonce(the nonce used to generate this block… to allow variations of the header and compute different hashes.), txn_count(number of transaction entries, this value is always 0.). + + +Now let's see the transaction which is another part of the block along with the header. + +The following is the looking of one transaction: +```json +{ + "hash": "4788c5ef8ffd0463422bcafdfab240f5bf0be690482ceccde79c51cfce209edd", + "ver": 1, + "vin_sz": 1, + "vout_sz": 2, + "lock_time": 0, + "size": 259, + "in": [ + { + "prev_out": { + "hash": "a6ae1beb8250a8fa6080749d5f82caee40f741d40957f0e8c4e4cc88830672ad", + "n": 1 + }, + "scriptSig": "3046022100aa39716861e508ae75ef577b3d83795a78d31cd72af0310b12ef8084cc16c9b8022100da72f62cdbd1b8d41cb4f8090e8c3b2929714279b3570962351dfbb739c2724601 0485c05717a0d35b2931c1395e9dcfffed3e67decff429477c48f6352da314c109ce0074bd1b991dd462ba16dbe9e4227193d35cc9342ea67f1b481054e345eef0" + }, + { + "prev_out": { + "hash": "fbcc98b9601e9498c2ac097a493c6eb20473c438bf84891d572109335792198d", + "n": 1 + }, + "scriptSig": "3045022100fc8e579f4cabda1e26a294b3f7f227087b64ca2451155b8747bd1f6c96780d6d022041912d38512030e1ec1d3df6b8d91d8b9aa4c564642fd7cafc48f97fd550100101 0482d593f88a39160eaed14470ee4dad283c29e88d9abb904f953115b1a93d6f3881d6f8c29c53ddb30b2d1c6b657068d60a93ed240d5efca247836f6395807bcd" + }, + { + "prev_out": { + "hash": "fbcc98b9601e9498c2ac097a493c6eb20473c438bf84891d572109335792198d", + "n": 3 + }, + "scriptSig": "3045022100fc8e579f4cabda1e26a294b3f7f227087b64ca2451155b8747bd1f6c96780d6d022041912d38512030e1ec1d3df6b8d91d8b9aa4c564642fd7cafc48f97fd550100101 0482d593f88a39160eaed14470ee4dad283c29e88d9abb904f953115b1a93d6f3881d6f8c29c53ddb30b2d1c6b657068d60a93ed240d5efca247836f6395807bcd" + } + ], + "out": [ + { + "value": "0.00010000", + "scriptPubKey": "OP_DUP OP_HASH160 edb82bd321c0c4b2b667c58e28ebc113d9bb38cd OP_EQUALVERIFY OP_CHECKSIG" + }, + { + "value": "0.01440000", + "scriptPubKey": "OP_DUP OP_HASH160 21d77a260a7d8fb1b0064f9e3c0b4e46a44e8199 OP_EQUALVERIFY OP_CHECKSIG" + } + ] +} +``` +Note that one block can have multiple transactions. + +A transaction is composed of several data: +1.TxIn. +A TxIn can have input(s). One input is composed of "prev_out" pointing to unspent output located in different transaction by specifying that output with the hash value of that transaction and the index number of that output in the correspond transaction and "scriptSig" playing a role of the signature. +2. TxOut. +A TxOut is composed of output(s). One output is composed of the value for an amount of coins which will be sent and a value of ScriptPubKey. +3. Other minimal data. +(1)hash is a transaction ID which is generated by twice hashing the entire of transaction(TxOut, TxIn, other minimal data) +(2)ver indicates the version of the transaction. +(3)vin_sz indicates the size of the TxIn. +(4)vout_sz indicates the size of the TxOut. +(5)lock_time +(6)size indicates the entire size of the transaction. + + +## Section2. Introducing the basic concepts and terms for the Blockchain system Part2 + +And each whole Blockchain located in each computer is termed by the ledger. And also each computer participating in the Bitcoin system network, with running the Bitcoin application and the whole blockchain which is termed the ledger, is termed the node. + +And among the nodes, particular nodes which make the block by gathering transactions generated and transferred by the Bitcoin system clients, are termed the miner. And as of writing this book, the block should be created every average 10 minutes. Sometimes the block is created in 6 minutes after the previous block had been created. Somtimes the block is created in 13 minutes after the previous block had been created. It means that it's the average 10 minutes. And the 10 minutes which is one of protocols is for Bitcoin blockchain system. Other kinds of blockchain system can have different protocols as to this time. This particular 10 minutes which is needed to create a new block is specified for some purposes such as sustaining a stability of the Bitcoin system, preventing malcious attempts from being happened too frequently and so on. + +And miner nodes compete to create the bloack and to append that bloack to the main chain. The block not appended into the main chain is termed the orphaned block. You only be able to get the coin from the coinbase transaction which is the first transaction of the newly created block and to get the mining fees generated by each transaction made by other Bitcoin system clients, in the block newly created by the corresponding miner who is getting fees in this block. + + +## Section3. More on the Blockchain system + +You might have noticed that while we proved ownership of the unspent TxOut. And even more, prior to mentioning the proof of the ownership, note that we have not yet proven the TxOut actually exists. This is where the main function of the Blockchain shines: The Blockchain is the database of all transactions that have happened since the the first Bitcoin transaction, known as the Genesis block. The Blockchain is duplicated all around the world. If you use Bitcoin Core, you have the whole Blockchain on your computer. Once a transaction appears on the Blockchain, it is very easy to prove its existence. @@ -16,3 +99,7 @@ As a user, you can verify that a specific transaction exists in the Blockchain i * Check the entire Blockchain, which at the time of this writing is several gigabytes in size. * Ask for a partial Merkel tree, which are a few kilobytes in size. We will talk about merkel trees later in relation to Simple Payment Verification. + + +Ref. +https://en.bitcoin.it/wiki/Protocol_documentation#Block_Headers diff --git a/bitcoin_transfer/payment_script.md b/bitcoin_transfer/payment_script.md index 9ebdc0e..892778e 100644 --- a/bitcoin_transfer/payment_script.md +++ b/bitcoin_transfer/payment_script.md @@ -1,5 +1,5 @@ -## ScriptPubKey {#payment-script} -You might not know that as far as the Blockchain is concerned, there is no such thing as a Bitcoin Address. Internally, the Bitcoin protocol identifies the recipient of Bitcoin by a **ScriptPubKey**. +## Chapter2. ScriptPubKey {#payment-script} +You might not know that, as far as the Blockchain is concerned, there is no such thing as a Bitcoin address. Internally, the Bitcoin protocol identifies the recipient of Bitcoin by a **ScriptPubKey**. ![](../assets/ScriptPubKey.png) A **ScriptPubKey** may look like this: @@ -12,38 +12,69 @@ We are able to generate the ScriptPubKey from the Bitcoin Address. This is a ste ![](../assets/BitcoinAddressToScriptPubKey.png) ```cs -var publicKeyHash = new KeyId("14836dbe7f38c5ac3d49e8d790af808a4ee9edcf"); +var publicKeyHashByHardCodedValue = new KeyId("97eb9da945f16139acb552a2de4081eb7f5176d9"); +Console.WriteLine($"publicKeyHashBySimpleWay: {publicKeyHashByHardCodedValue}"); +//Output: +//97eb9da945f16139acb552a2de4081eb7f5176d9 -var testNetAddress = publicKeyHash.GetAddress(Network.TestNet); -var mainNetAddress = publicKeyHash.GetAddress(Network.Main); +//Generate bitcoin addresses for each network. +var bitcoinAddressForTestNet = publicKeyHashByHardCodedValue.GetAddress(Network.TestNet); +var bitcoinAddressForMainNet = publicKeyHashByHardCodedValue.GetAddress(Network.Main); +Console.WriteLine($"bitcoinAddressForTestNet {bitcoinAddressForTestNet}"); +//Output: +//muNEau1yEUXmTcU8ns6GYhHfSCsMjseuNB +Console.WriteLine($"bitcoinAddressForMainNet {bitcoinAddressForMainNet}"); +//Output: +//1ErHHqvzRT6WgVzX5J7tin5LaDGev2UobP -Console.WriteLine(mainNetAddress.ScriptPubKey); // OP_DUP OP_HASH160 14836dbe7f38c5ac3d49e8d790af808a4ee9edcf OP_EQUALVERIFY OP_CHECKSIG -Console.WriteLine(testNetAddress.ScriptPubKey); // OP_DUP OP_HASH160 14836dbe7f38c5ac3d49e8d790af808a4ee9edcf OP_EQUALVERIFY OP_CHECKSIG +//Generate a ScriptPubKey from a Bitcoin address. +Console.WriteLine(bitcoinAddressForMainNet.ScriptPubKey); +//Output: +//OP_DUP OP_HASH160 97eb9da945f16139acb552a2de4081eb7f5176d9 OP_EQUALVERIFY OP_CHECKSIG +Console.WriteLine(bitcoinAddressForTestNet.ScriptPubKey); +//Output: +//OP_DUP OP_HASH160 97eb9da945f16139acb552a2de4081eb7f5176d9 OP_EQUALVERIFY OP_CHECKSIG ``` -Notice the **ScriptPubKey** for testnet and mainnet address is the same? -Notice the **ScriptPubKey** contains the hash of the public key? -We will not go into the details yet, but note that the **ScriptPubKey** appears to have nothing to do with the Bitcoin Address, but it does show the hash of the public key. +Can you notice the ScriptPubKeys (bitcoinAddressForMainNet.ScriptPubKey and bitcoinAddressForTestNet.ScriptPubKey) generated from each Bitcoin address for the TestNet and the MainNet are exactly identical? +Can you notice the **ScriptPubKey** contains the hash of the public key hash (97eb9da945f16139acb552a2de4081eb7f5176d9)? +We will not go into the details yet. However, the **ScriptPubKey** is looking like it has nothing to do with the Bitcoin address, just with showing the public key hash value from a part of the entire ScriptPubKey. -Bitcoin Addresses are composed of a version byte which identifies the network where to use the address and the hash of a public key. So we can go backwards and generate a bitcoin address from the **ScriptPubKey** and the network identifier. +Bitcoin addresse is composed of a "version byte" which identifies the network type where for the bitcoin address to being used and the "hash of a public key". So we can go backwards and generate a bitcoin address from the **ScriptPubKey** and the network identifier. ```cs -var paymentScript = publicKeyHash.ScriptPubKey; -var sameMainNetAddress = paymentScript.GetDestinationAddress(Network.Main); -Console.WriteLine(mainNetAddress == sameMainNetAddress); // True +//Generate a ScriptPubKey from publicKeyHash. +var scriptPubKeyForPayment = publicKeyHashForThisExample.ScriptPubKey; + +//Get a Bitcoin address by specifying a network identifier on the ScriptPubKey. +var bitcoinAddressFromSPKForMainNet = scriptPubKeyForPayment.GetDestinationAddress(Network.Main); +Console.WriteLine(bitcoinAddressForMainNet == bitcoinAddressFromSPKForMainNet); +//Output: +//True ``` -It is also possible to retrieve the hash from the **ScriptPubKey** and generate a Bitcoin Address from it: +It is also possible to retrieve the public key hash value from the ScriptPubKey and also generate a Bitcoin address by specifying a network identifier on the public key hash generated in this way. ```cs -var samePublicKeyHash = (KeyId) paymentScript.GetDestination(); -Console.WriteLine(publicKeyHash == samePublicKeyHash); // True -var sameMainNetAddress2 = new BitcoinPubKeyAddress(samePublicKeyHash, Network.Main); -Console.WriteLine(mainNetAddress == sameMainNetAddress2); // True +//Get the public key hash value from the ScriptPubKey. +var publicKeyHashFromSPK = (KeyId)scriptPubKeyForPayment.GetDestination(); +Console.WriteLine(publicKeyHashForThisExample == publicKeyHashFromSPK); +//Output: +//True + +//Get the Bitcoin address by using the publick key hash value retrieved from the ScriptPubKey from above code and network identifier. +var bitcoinAddressGotAgain = new BitcoinPubKeyAddress(publicKeyHashFromSPK, Network.Main); +Console.WriteLine(bitcoinAddressForMainNet == bitcoinAddressGotAgain); +//Output: +//True ``` -> **Note:** A ScriptPubKey does not necessarily contain the hashed public key(s) permitted to spend the bitcoin. +> **Note:** A ScriptPubKey does not necessarily contain the hashed public key(s) permitted to spend the bitcoin like this: +``` +OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG +``` So now you understand the relationship between a Private Key, a Public Key, a Public Key Hash, a Bitcoin Address and a ScriptPubKey. -In the remainder of this book, we will exclusively use **ScriptPubKey**. A Bitcoin Address is only a user interface concept. +In the remainder of this book, we will exclusively use a **ScriptPubKey**. +And again, a Bitcoin address representing a recipient is just the address human-readable for the UI layer like a wallet software. The address representing a recipient, which is blockchain system readable, is the ScriptPubKey which is used in a TxOut of a transaction. diff --git a/bitcoin_transfer/private_key.md b/bitcoin_transfer/private_key.md index 927794d..6dc6f82 100644 --- a/bitcoin_transfer/private_key.md +++ b/bitcoin_transfer/private_key.md @@ -1,45 +1,77 @@ -## Private key {#private-key} +## Chapter3. Private key {#private-key} -Private keys are often represented in Base58Check called a **Bitcoin Secret** (also known as **Wallet Import Format** or simply **WIF**), like Bitcoin Addresses. +Private keys are often represented in Base58Check encoding scheme, to use the encoded private key in the UI layer. And private key represented in Base58Check is especially called a **Bitcoin Secret**. Bitcoin secret is also known as a **Wallet Import Format** or simply **WIF** because a "Bitcoin secret" is usually used with a Bitcoin wallet which is a kind of an UI tool, along with a "Bitcoin address". Usually a Bitcoin secret is used for signing a signature for the coin and proof of ownership for the coin. And a Bitcoin address in the UI layer is used for representing a recipient to which the coin will be sent. ![](../assets/BitcoinSecret.png) ```cs -Key privateKey = new Key(); // generate a random private key -BitcoinSecret mainNetPrivateKey = privateKey.GetBitcoinSecret(Network.Main); // generate our Bitcoin secret(also known as Wallet Import Format or simply WIF) from our private key for the mainnet -BitcoinSecret testNetPrivateKey = privateKey.GetBitcoinSecret(Network.TestNet); // generate our Bitcoin secret(also known as Wallet Import Format or simply WIF) from our private key for the testnet -Console.WriteLine(mainNetPrivateKey); // L5B67zvrndS5c71EjkrTJZ99UaoVbMUAK58GKdQUfYCpAa6jypvn -Console.WriteLine(testNetPrivateKey); // cVY5auviDh8LmYUW8AfafseD6p6uFoZrP7GjS3rzAerpRKE9Wmuz - -bool WifIsBitcoinSecret = mainNetPrivateKey == privateKey.GetWif(Network.Main); -Console.WriteLine(WifIsBitcoinSecret); // True -``` +//Generate one random private key. +Key privateKey = new Key(); -Note that it is easy to go from **BitcoinSecret** to private **Key**. On the other hand, it is impossible to go from a Bitcoin Address to Public Key because the Bitcoin Address contains a hash of the Public Key, not the Public Key itself. -Process this information by examining the similarities between these two codeblocks: +//Generate a Bitcoin secret for the MainNet, which is nothing but a private key represented in Base58Check binary-to-text encoding scheme. +BitcoinSecret privateKeyForMainNet = privateKey.GetBitcoinSecret(Network.Main); +//Generate a Bitcoin secret for the TestNet, which is nothing but a private key represented in Base58Check binary-to-text encoding scheme. +BitcoinSecret privateKeyForTestNet = privateKey.GetBitcoinSecret(Network.TestNet); -```cs -Key privateKey = new Key(); // generate a random private key -BitcoinSecret bitcoinSecret = privateKey.GetWif(Network.Main); // L5B67zvrndS5c71EjkrTJZ99UaoVbMUAK58GKdQUfYCpAa6jypvn -Key samePrivateKey = bitcoinSecret.PrivateKey; -Console.WriteLine(samePrivateKey == privateKey); // True -``` +Console.WriteLine($"privateKeyForMainNet: {privateKeyForMainNet}"); +//Output: +//L5DZpEdbDDhhk3EqtktmGXKv3L9GxttYTecxDhM5huLd82qd9uvo +Console.WriteLine($"privateKeyForTestNet: {privateKeyForTestNet}"); +//Output: +//cVaZH9dSeHPxuUi7HAhtdqpyfZSgdLzEXgmRL7obD1zdNmxcW9aL -```cs -PubKey publicKey = privateKey.PubKey; -BitcoinPubKeyAddress bitcoinPublicKey = publicKey.GetAddress(Network.Main); // 1PUYsjwfNmX64wS368ZR5FMouTtUmvtmTY -//PubKey samePublicKey = bitcoinPublicKey.ItIsNotPossible; +//You can also generate a private key by invoking GetWif() on the private key by additionally specifying a network identifier. +//Note that we're using the same private key generated from above. +BitcoinSecret privateKeyByGetWifMethod = privateKey.GetWif(Network.Main); +Console.WriteLine(privateKeyByGetWifMethod); +//Output: +//L5B67zvrndS5c71EjkrTJZ99UaoVbMUAK58GKdQUfYCpAa6jypvn + +bool wifIsPrivateKey = privateKeyForMainNet == privateKey.GetWif(Network.Main); +Console.WriteLine(wifIsPrivateKey); +//Output: +//True ``` -### Exercise: -1. Generate a private key on the mainnet and note it. -2. Get the corresponding address. -3. Send bitcoins to it. As much as you cannot afford to lose, so it will keep you focused and motivated to get them back during the following lessons. +Note that it is easy to go from a **Bitcoin secret** to a **private key**. +Recall that a Bitcoin secret is nothing but a private key just represented in Base58Check from a private key, which is often used in UI layer in Bitcoin system such as via wallet software. In the NBitcoin, when you instantiate a key object by a "new Key()", under the hood, you also invoke a secure PRNG to generate a random key data for a private key which will be stored in the key object. +On the other hand, it is impossible to go from a Bitcoin address to a public key because the Bitcoin address is generated from a hash of the public key(and + network identifier), not the public key itself. +Process this information by examining the similarities between these two codeblocks: + +```cs +//Get the Bitcoin secret by invoking GetWif() on the private key with passing additionally the network identifier. +BitcoinSecret bitcoinSecretByGetWif = privateKey.GetWif(Network.Main); +//Get the Bitcoin secret by invoking GetBitcoinSecret() on the private key with passing additionally the network identifier. +BitcoinSecret bitcoinSecretByGetBitcoinSecret = privateKey.GetBitcoinSecret(Network.Main); - +//Get the private key from the Bitcoin secret. +var privateKeyFromBsByGetWif = bitcoinSecretByGetWif.PrivateKey; +var privateKeyFromBsByGetBitcoinSecret = bitcoinSecretByGetBitcoinSecret.PrivateKey; +Console.WriteLine($"privateKeyFromBsByGetWif: {privateKeyFromBsByGetWif.ToString(Network.Main)}"); +Console.WriteLine($"privateKeyFromBsByGetBitcoinSecret: {privateKeyFromBsByGetBitcoinSecret.ToString(Network.Main)}"); +//L5DZpEdbDDhhk3EqtktmGXKv3L9GxttYTecxDhM5huLd82qd9uvo +//L5DZpEdbDDhhk3EqtktmGXKv3L9GxttYTecxDhM5huLd82qd9uvo +Console.WriteLine(privateKey==privateKeyFromBsByGetWif); +//Output: +//True +``` +You can get the Bitcoin address from the public key by additionally specifying the network identifier. +But it's impossible to get the public key from the Bitcoin address because the Bitcoin address is generated from the public key hash value(plus network identifier), not public key itself. +```cs +PubKey publicKey = privateKey.PubKey; +BitcoinPubKeyAddress bitcoinAddress = publicKey.GetAddress(Network.Main); +Console.WriteLine($"bitcoinAddress: {bitcoinAddress}"); +//Output: +//1ErHHqvzRT6WgVzX5J7tin5LaDGev2UobP +//PubKey publicKeyFromBitcoinAddress = bitcoinAddress.ItIsNotPossible; +``` +### Exercise: +1. Generate a private key on the MainNet and note it. +2. Get the Bitcoin address related to that private key. +3. Send bitcoins to that Bitcoin address. As much as you cannot afford to lose, so it will keep you focused and motivated to get them back during the following lessons. diff --git a/bitcoin_transfer/proof_of_ownership_as_an_authentication_method.md b/bitcoin_transfer/proof_of_ownership_as_an_authentication_method.md index f4fe840..d9144ad 100644 --- a/bitcoin_transfer/proof_of_ownership_as_an_authentication_method.md +++ b/bitcoin_transfer/proof_of_ownership_as_an_authentication_method.md @@ -1,34 +1,41 @@ -## Proof of ownership as an authentication method {#proof-of-ownership-as-an-authentication-method} -> [[2016.05.02](https://www.youtube.com/watch?v=dZNtbAFnr-0)] My name is Craig Wright and I am about to demonstrate a signing of a message with the public key that is associated with the first transaction ever done in Bitcoin. +# Chapter8. Proof of an ownership as an authentication method {#proof-of-ownership-as-an-authentication-method} +> [Click to watch a video on YouTube [2016.05.02](https://www.youtube.com/watch?v=dZNtbAFnr-0)] My name is Craig Wright and I am about to demonstrate a signing of a message with the public key that is associated with the first transaction ever done in Bitcoin. ```cs -var bitcoinPrivateKey = new BitcoinSecret("XXXXXXXXXXXXXXXXXXXXXXXXXX"); - +var bitcoinSecretOfCraig = new BitcoinSecret("KzgjNRhcJ3HRjxVdFhv14BrYUKrYBzdoxQyR2iJBHG9SNGGgbmtC"); var message = "I am Craig Wright"; -string signature = bitcoinPrivateKey.PrivateKey.SignMessage(message); -Console.WriteLine(signature); // IN5v9+3HGW1q71OqQ1boSZTm0/DCiMpI8E4JB1nD67TCbIVMRk/e3KrTT9GvOuu3NGN0w8R2lWOV2cxnBp+Of8c= +Console.WriteLine($"bitcoinSecretOfCraig.PrivateKey: {bitcoinSecretOfCraig.PrivateKey}"); +string signature = bitcoinSecretOfCraig.PrivateKey.SignMessage(message); +Console.WriteLine($"signature: {signature}"); +//Output: +//IN5v9+3HGW1q71OqQ1boSZTm0/DCiMpI8E4JB1nD67TCbIVMRk/e3KrTT9GvOuu3NGN0w8R2lWOV2cxnBp+Of8c= +Console.WriteLine($"bitcoinPrivateKey.Network: {bitcoinSecretOfCraig.Network}"); ``` Was that so hard? -You may remember Craig Wright, who really wanted us to believe he is Satoshi Nakamoto. +You may remember Craig Wright who really wanted us to believe he is Satoshi Nakamoto. He had successfully convinced a handful of influential Bitcoin people and journalists with some social engineering. -Fortunately digital signatures do not work that way. -Let's quickly find on the [Internet](https://en.bitcoin.it/wiki/Genesis_block) the first ever bitcoin address, associated with the genesis block: [1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa](https://blockchain.info/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa) and verify his claim: +Fortunately, digital signatures do not work that way. +Let's quickly find the first ever bitcoin address associated with the genesis block, on the [Internet](https://en.bitcoin.it/wiki/Genesis_block): +1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa +And verify his claim by the following code. ```cs -var message = "I am Craig Wright"; -var signature = "IN5v9+3HGW1q71OqQ1boSZTm0/DCiMpI8E4JB1nD67TCbIVMRk/e3KrTT9GvOuu3NGN0w8R2lWOV2cxnBp+Of8c="; +var messageWrittenByCraig = "I am Craig Wright"; +var signatureByCraig = "IN5v9+3HGW1q71OqQ1boSZTm0/DCiMpI8E4JB1nD67TCbIVMRk/e3KrTT9GvOuu3NGN0w8R2lWOV2cxnBp+Of8c="; +var bitcoinAddressOfTheFirstEver = new BitcoinPubKeyAddress("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"); +//Verify the message and signature written by Craig by comparing them to ones located in the bitcoin address of the first ever. +bool isCraigWrightSatoshi = bitcoinAddressOfTheFirstEver.VerifyMessage(messageWrittenByCraig, signatureByCraig); +Console.WriteLine($"isCraigWrightSatoshi: {isCraigWrightSatoshi}"); +``` -var address = new BitcoinPubKeyAddress("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"); -bool isCraigWrightSatoshi = address.VerifyMessage(message, signature); +SPOILER ALERT! The bool will be false. -Console.WriteLine("Is Craig Wright Satoshi? " + isCraigWrightSatoshi); -``` +It is how you prove you are the owner of the Bitcoin address by using message and signature without moving coins. -SPOILER ALERT! The bool will be false. -Here is how you prove you are the owner of an address without moving coins: +**Exercise:** Verify that Nicolas sensei is not lying! **Address:** [1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB](https://blockchain.info/address/1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB) @@ -38,9 +45,11 @@ Nicolas Dorier Book Funding Address H1jiXPzun3rXi0N9v9R5fAWrfEae9WPmlL5DJBj1eTStSvpKdRR8Io6/uT9tGH/3OnzG6ym5yytuWoA9ahkC3dQ= This constitutes proof that Nicolas Dorier owns the private key of the book. -**Exercise:** Verify that Nicolas sensei is not lying! + + +**Exercise:** Get the first Bitcoin address which was generated by Satoshi Nakamoto. -### Sidenote -Do you know how PGP works? Pretty similar, right? +## Sidenote +Do you know how PGP(Pretty Good Privacy) works? Pretty similar, right? Maybe this can be the foundation of a more user friendly PGP alternative. -Please build it on top of NBitcoin :-) +Please build it on top of the NBitcoin :-) diff --git a/bitcoin_transfer/spend_your_coin.md b/bitcoin_transfer/spend_your_coin.md index 1ec0f6b..dd2d4bd 100644 --- a/bitcoin_transfer/spend_your_coin.md +++ b/bitcoin_transfer/spend_your_coin.md @@ -21,18 +21,22 @@ Console.WriteLine(bitcoinPrivateKey); Console.WriteLine(address); ``` -Note the **bitcoinPrivateKey** and the **address**, send some coins there and note the transaction id (you can find it, probably, in your wallet software or with a blockexplorer, like [blockchain.info](http://blockchain.info/)). +Note the **bitcoinPrivateKey** and the **address** from above codes. And send some coins there and note the transaction id (you can find it, probably, in your wallet software or with a blockexplorer like [blockchain.info](http://blockchain.info/)). Import your private key: ```cs var bitcoinPrivateKey = new BitcoinSecret("cSZjE4aJNPpBtU6xvJ6J4iBzDgTmzTjbq8w2kqnYvAprBCyTsG4x"); -var network = bitcoinPrivateKey.Network; +var network = bitcoinPrivateKey.Network; var address = bitcoinPrivateKey.GetAddress(); -Console.WriteLine(bitcoinPrivateKey); // cSZjE4aJNPpBtU6xvJ6J4iBzDgTmzTjbq8w2kqnYvAprBCyTsG4x -Console.WriteLine(address); // mzK6Jy5mer3ABBxfHdcxXEChsn3mkv8qJv +Console.WriteLine(bitcoinPrivateKey); +//Output: +//cSZjE4aJNPpBtU6xvJ6J4iBzDgTmzTjbq8w2kqnYvAprBCyTsG4x +Console.WriteLine(address); +//Output: +//mzK6Jy5mer3ABBxfHdcxXEChsn3mkv8qJv ``` And finally get the transaction info: @@ -41,7 +45,9 @@ var client = new QBitNinjaClient(network); var transactionId = uint256.Parse("e44587cf08b4f03b0e8b4ae7562217796ec47b8c91666681d71329b764add2e3"); var transactionResponse = client.GetTransaction(transactionId).Result; -Console.WriteLine(transactionResponse.TransactionId); // e44587cf08b4f03b0e8b4ae7562217796ec47b8c91666681d71329b764add2e3 +Console.WriteLine(transactionResponse.TransactionId); +//Output: +//e44587cf08b4f03b0e8b4ae7562217796ec47b8c91666681d71329b764add2e3 Console.WriteLine(transactionResponse.Block.Confirmations); ``` @@ -83,7 +89,7 @@ Constructing the **TxOut** and adding it to the transaction is the answer to the The donation address of this book is: [1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB](https://blockchain.info/address/1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB) This money goes into my "Coffee and Sushi Wallet" that will keep me fed and compliant while writing the rest of the book. -If you succeed in completing this challenge you will be able to find your contribution amongst the **Hall of the Makers** on http://n.bitcoin.ninja/ (ordered by generosity). +If you succeed in completing this challenge, you will be able to find your contribution amongst the **Hall of the Makers** on http://n.bitcoin.ninja/ (ordered by generosity). ```cs var hallOfTheMakersAddress = new BitcoinPubKeyAddress("1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB"); ``` @@ -93,19 +99,25 @@ var hallOfTheMakersAddress = BitcoinAddress.Create("mzp4No5cmCXjZUpf112B1XWsvWBf ``` ### How much? -If you want to send **0.5 BTC** from a **transaction input** with **1 BTC** you actually have to spend it all! +If you want to send **0.5** BTC from an **unspent output** which holds 1 BTC, you actually have to spend it all! +And you will get the changes back to your Bitcoin address. As the diagram shows below, your **transaction output** specifies **0.5** BTC to Hall of The Makers and **0.4999** back to you. -What happens to the remaining **0.0001 BTC**? This is the miner fee in order to incentivize them to add this transaction into their next block. +What happens to the remaining **0.0001** BTC? This is the miner fee in order to incentivize them to add this transaction into their next block. ![](../assets/SpendTx.png) +By this codes, we're going to generate TxOuts with hardcoded amounts of coins. ```cs +//Generate a TxOut for hallOfTheMakers. TxOut hallOfTheMakersTxOut = new TxOut() { + //Set 0.5 bitcoins to be sent. Value = new Money((decimal)0.5, MoneyUnit.BTC), + //Set a ScriptPubKey for the recipient. ScriptPubKey = hallOfTheMakersAddress.ScriptPubKey }; +//Generate a TxOut for changeBack(1-0.5-fee). TxOut changeBackTxOut = new TxOut() { Value = new Money((decimal)0.4999, MoneyUnit.BTC), @@ -117,18 +129,22 @@ transaction.Outputs.Add(changeBackTxOut); ``` We can do some fine tuning here. -You can check the address I am working with in this chapter's examples on a blockexplorer (I am working on the testnet): http://tbtc.blockr.io/address/info/mzK6Jy5mer3ABBxfHdcxXEChsn3mkv8qJv +You can check the address I am working with in this chapter's examples on a blockexplorer. +I am working on the testnet: +http://tbtc.blockr.io/address/info/mzK6Jy5mer3ABBxfHdcxXEChsn3mkv8qJv + +By this codes, we're going to generate TxOuts by calculating coins not with hardcoded amounts of ones. ```cs -// How much you want to TO +//First, set the amount of coin to be sent. var hallOfTheMakersAmount = new Money(0.5m, MoneyUnit.BTC); -/* At the time of writing the mining fee is 0.05usd - * Depending on the market price and - * On the currently advised mining fee, - * You may consider to increase or decrease it -*/ + +//Secend, set the amount of a transaction fee which will be sent to the miner who created the block including a transaction I'm writing here. +//At the time of writing, the mining fee is 0.05usd, depending on the market price and on the currently advised mining fee. +//You may consider to increase or decrease it. var minerFee = new Money(0.0001m, MoneyUnit.BTC); -// How much you want to spend FROM + +//Get the entire coins that are sent from a specific TxOut(in this case, second one since its index number is 1) of another previous transaction. var txInAmount = receivedCoins[(int) outPointToSpend.N].TxOut.Amount; Money changeBackAmount = txInAmount - hallOfTheMakersAmount - minerFee; ``` @@ -157,7 +173,7 @@ transaction.Outputs.Add(changeBackTxOut); ### Message on The Blockchain Now add your feedback! This must be less than 40 bytes, or it will crash the application. -This feedback, along with your transaction will appear (after your transaction is confirmed) in the [Hall of The Makers](http://n.bitcoin.ninja/). +This feedback along with your transaction will appear after your transaction is confirmed in the [Hall of The Makers](http://n.bitcoin.ninja/). ```cs var message = "nopara73 loves NBitcoin!"; @@ -170,7 +186,7 @@ transaction.Outputs.Add(new TxOut() ``` To sum up take a look at my whole transaction before we sign it: -I have 3 **TxOut**, 2 with **value**, 1 without **value** (which contains the message). You can notice the differences between the **scriptPubKey**s of the "normal" **TxOut**s and the **scriptPubKey** of the **TxOut** with the message: +I have 3 **TxOut**, 2 with **value**, 1 without **value** which contains just a message. You can notice the differences between the **scriptPubKey**s of the "normal" **TxOut**s and the **scriptPubKey** of the **TxOut** with the message: ```json { @@ -206,12 +222,13 @@ I have 3 **TxOut**, 2 with **value**, 1 without **value** (which contains the me } ``` -Take a closer look at **TxIn**. We have **prev_out** and **scriptSig** there. -**Exercise:** try to figure out what **scriptSig** will be and how to get it in our code before you read further! +Take a closer look at **TxIn**. We have **prev_out** and **scriptSig** there. + +**Exercise:** Try to figure out what **scriptSig** will be and how to get it in our code before you read further! Let's check out the **hash** of **prev_out** in a blockexplorer: http://tbtc.blockr.io/api/v1/tx/info/e44587cf08b4f03b0e8b4ae7562217796ec47b8c91666681d71329b764add2e3 -In **prev_out** **n** is 1. Since we are indexing from 0, this means I want to spend the second output of the transaction. -In the blockexplorer we can see the corresponding address is ```mzK6Jy5mer3ABBxfHdcxXEChsn3mkv8qJv``` and I can get the scriptSig from the address like this: +In **prev_out**, **n** is 1. Since we are indexing from 0, this means I want to spend the second output of the transaction. +In the blockexplorer we can see the corresponding address is ```mzK6Jy5mer3ABBxfHdcxXEChsn3mkv8qJv``` and I can get and set a scriptSig from the address via a ScriptPubKey like this: ```cs var address = BitcoinAddress.Create("mzK6Jy5mer3ABBxfHdcxXEChsn3mkv8qJv"); @@ -220,17 +237,17 @@ transaction.Inputs[0].ScriptSig = address.ScriptPubKey; ### Sign your transaction -Now that we have created the transaction, we must sign it. In other words, you will have to prove that you own the TxOut that you referenced in the input. +Now that we have created the transaction, we must sign it. In other words, you will have to prove that you own the TxOut located in another previous transaction, that you referenced in the input. Signing can be [complicated](https://en.bitcoin.it/w/images/en/7/70/Bitcoin_OpCheckSig_InDetail.png), but we’ll make it simple. -First let's revisit the **scriptSig** of **in** and how we can get it from code. Remember, we copy/pasted the address above from a blockexplorer, now let's get it from our QBitNinja transactionResponse: +First let's revisit the **scriptSig** of **input** and see how we can get it from codes. Remember, we copy/pasted the address above from a blockexplorer, As we've already seen how to get and set a ScriptSig from above code, similarly, now let's get set a ScriptPubKey from a private key via a ScriptPubKey, using our QBitNinja transactionResponse: ```cs transaction.Inputs[0].ScriptSig = bitcoinPrivateKey.ScriptPubKey; ``` -Then you need to provide your private key in order to sign the transaction: +Then, you need to provide your private key in order to sign the transaction: ```cs transaction.Sign(bitcoinPrivateKey, false); @@ -238,6 +255,7 @@ transaction.Sign(bitcoinPrivateKey, false); ### Propagate your transactions Congratulations, you have signed your first transaction! Your transaction is ready to roll! All that is left is to propagate it to the network so the miners can see it. + #### With QBitNinja: ```cs BroadcastResponse broadcastResponse = client.Broadcast(transaction).Result; diff --git a/bitcoin_transfer/the_blockchain_is_more_than_just_bitcoin.md b/bitcoin_transfer/the_blockchain_is_more_than_just_bitcoin.md index cd88c45..f92dca2 100644 --- a/bitcoin_transfer/the_blockchain_is_more_than_just_bitcoin.md +++ b/bitcoin_transfer/the_blockchain_is_more_than_just_bitcoin.md @@ -1,11 +1,15 @@ -## “The Blockchain is more than just Bitcoin” {#the-blockchain-is-more-than-just-bitcoin} +## Chapter6. “The Blockchain is more than just the Bitcoin” {#the-blockchain-is-more-than-just-bitcoin} -The interesting thing is that this same sentence is used by two different groups of people. -It is used by Bitcoin-As-A-Currency believers as argument for their bullish prediction of Bitcoin’s value. -It is also used by those who do not believe in the success of the currency, as an attempt to explain why Bitcoin has so much interest. +“The Blockchain is more than just the Bitcoin” -But there is one thing we all agree on: an immutable database that cannot be censored, tampered with, or erased that is duplicated all around the world will have tremendous impact on other industries. +The interesting thing is that this sentence is used by two different groups of people. +It is used by Bitcoin-As-a-Currency believers as an argument for their bullish prediction of Bitcoin’s value. +It is also used by those who do not believe in the success of the Bitcoin as a currency, attempting to explain why Bitcoin has so much interests rather than just a currency aspect of a Bitcoin. -Notaries who record facts that can be used in court could store their documents permanently in The Blockchain. Audits can become automatic and provable when assets and ownership are stored and transferred on The Blockchain. All Money Transmitters can prove their solvency publicly. Automatic trading scripts can trade between themselves without human intervention or the need for authorization from a central authority. +But there is one thing we all agree on: an immutable database that cannot be censored, tampered with, or erased, but that is duplicated all around the world will have tremendous impact on other industries. + +Notaries who record facts that can be used in court could store their documents permanently in the Blockchain. +Audits can become automatic and provable when assets and ownership are stored and transferred on the Blockchain. +All Money Transmitters can prove their solvency publicly. Automatic trading scripts can trade between themselves without a human intervention or a need for authorization from a central authority. In the rest of this book we will explore the fundamentals required to enable all of these technologies and more. It all starts with spending a bitcoin. diff --git a/bitcoin_transfer/transaction.md b/bitcoin_transfer/transaction.md index 0674e54..edce889 100644 --- a/bitcoin_transfer/transaction.md +++ b/bitcoin_transfer/transaction.md @@ -4,22 +4,29 @@ A transaction may have no recipient, or it may have several. **The same can be said for senders!** On the Blockchain, the sender and recipient are always abstracted with a ScriptPubKey, as we demonstrated in previous chapters. -If you use Bitcoin Core your Transactions tab will show the transaction, like this: +If you use Bitcoin Core, your Transactions tab will show the transaction, like this: ![](../assets/BitcoinCoreTransaction.png) For now we are interested in the **Transaction ID**. In this case, it is ```f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94``` -> **Note:** The Transaction ID is defined by SHA256(SHA256(txbytes)) +> **Note:** The value of the Transaction ID is generated by twice hashing the entire of transaction which is composed of a list of "inputs" composed of the part of prev_out pointing to the unspent transaction's outputs and the part of signature(scriptSig), "outputs" composed of a ScriptPubKey and its value, and "several minimal data". + +The process can be expressed like this: +SHA256(SHA256(txbytes)) > **Note:** Do NOT use the Transaction ID to handle unconfirmed transactions. The Transaction ID can be manipulated before it is confirmed. This is known as “Transaction Malleability.” -You can review the transaction on a block explorer like Blockchain.info: https://blockchain.info/tx/f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94 +You can review a specific transaction on a block explorer like Blockchain.info: +https://blockchain.info/tx/f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94 + But as a developer you will probably want a service that is easier to query and parse. As a C# developer and an NBitcoin user Nicolas Dorier's [QBit Ninja](http://docs.qbitninja.apiary.io/) will definitely be your best choice. It is an open source web service API to query the blockchain and for tracking wallets. -QBit Ninja depends on [NBitcoin.Indexer](https://github.com/MetacoSA/NBitcoin.Indexer) which relies on Microsoft Azure Storage. C# developers are expected to use the [NuGet client package](http://www.nuget.org/packages/QBitninja.Client) instead of developing a wrapper around this API. +QBitNinja depends on [NBitcoin.Indexer](https://github.com/MetacoSA/NBitcoin.Indexer) which relies on Microsoft Azure Storage. C# developers are expected to use the [NuGet client package](http://www.nuget.org/packages/QBitninja.Client) instead of developing a wrapper around this API. -If you go to http://api.qbit.ninja/transactions/f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94 you will see the raw bytes of your transaction. +If you go to: +http://api.qbit.ninja/transactions/f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94 +you will see the raw bytes of your transaction. ![](../assets/RawTx.png) @@ -29,16 +36,16 @@ You can parse the transaction from hex with the following code: Transaction tx = new Transaction("0100000..."); ``` -Quickly close the tab, before it scares you away, QBit Ninja queries the API and parses the information so go ahead and install **QBitNinja.Client** NuGet package. +Quickly close the tab, before it scares you away. Since the QBit Ninja queries the API and parses the information so go ahead and install **QBitNinja.Client** NuGet package. ![](../assets/QBitNuGet.png) -Query the transaction by id: +Query the transaction by ID: ```cs // Create a client QBitNinjaClient client = new QBitNinjaClient(Network.Main); -// Parse transaction id to NBitcoin.uint256 so the client can eat it +// Parse transaction ID to NBitcoin.uint256 so the client can eat it var transactionId = uint256.Parse("f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94"); // Query the transaction GetTransactionResponse transactionResponse = client.GetTransaction(transactionId).Result; @@ -50,11 +57,19 @@ The type of **transactionResponse** is **GetTransactionResponse**. It lives unde NBitcoin.Transaction transaction = transactionResponse.Transaction; ``` -Let's see an example getting back the transaction id with both classes: +Let's see an example getting back the transaction ID by both classes, GetTransactionResponse and Transaction: + ```cs -Console.WriteLine(transactionResponse.TransactionId); // f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94 -Console.WriteLine(transaction.GetHash()); // f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94 +//Get the Transaction ID simply by using the TransactionId property of GetTransactionResponse class. +Console.WriteLine(transactionResponse.TransactionId); +//Output: +//f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94 + +//Get the Transaction ID by hashing the retrieved transaction. +Console.WriteLine(transaction.GetHash()); +//Output: +//f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94 ``` **GetTransactionResponse** has additional information about the transaction like the value and scriptPubKey of the inputs being spent in the transaction. @@ -62,24 +77,29 @@ Console.WriteLine(transaction.GetHash()); // f13dc48fb035bbf0a6e989a26b3ecb57b84 The relevant parts for now are the **inputs** and **outputs**. You can see there is only one output in our transaction. `13.19683492` bitcoins are sent to that ScriptPubKey. + +## Examine the RECEIVED COINS by using QBitNinja's GetTransactionResponse class ```cs List receivedCoins = transactionResponse.ReceivedCoins; foreach (var coin in receivedCoins) { Money amount = (Money) coin.Amount; - Console.WriteLine(amount.ToDecimal(MoneyUnit.BTC)); var paymentScript = coin.TxOut.ScriptPubKey; - Console.WriteLine(paymentScript); // It's the ScriptPubKey - var address = paymentScript.GetDestinationAddress(Network.Main); - Console.WriteLine(address); // 1HfbwN6Lvma9eDsv7mdwp529tgiyfNr7jc + //Print each ScriptPubKey by executing foreach loop. + Console.WriteLine(paymentScript); + //Get a Bitcoin address. + //Recall that we can get a Bitcoin address from a ScriptPubKey by specifying a network identifier by processing backwards. + var bitcoinAddressWithQG = paymentScript.GetDestinationAddress(Network.Main); + Console.WriteLine(bitcoinAddressWithQG); + //Output: + //1HfbwN6Lvma9eDsv7mdwp529tgiyfNr7jc Console.WriteLine(); } ``` -We have written out some information about the RECEIVED COINS using QBitNinja's GetTransactionResponse class. -**Exercise**: Write out the same information about the SPENT COINS using QBitNinja's GetTransactionResponse class! +## Examine the RECEIVED COINS by using NBitcoin's Transaction class Let's see how we can get the same information about the RECEIVED COINS using NBitcoin's Transaction class. ```cs @@ -90,23 +110,32 @@ foreach (TxOut output in outputs) Console.WriteLine(amount.ToDecimal(MoneyUnit.BTC)); var paymentScript = output.ScriptPubKey; - Console.WriteLine(paymentScript); // It's the ScriptPubKey - var address = paymentScript.GetDestinationAddress(Network.Main); - Console.WriteLine(address); + //It's the ScriptPubKey. + Console.WriteLine(paymentScript); + var bitcoinAddressWithNT = paymentScript.GetDestinationAddress(Network.Main); + Console.WriteLine(bitcoinAddressWithNT); + //Output: + //1HfbwN6Lvma9eDsv7mdwp529tgiyfNr7jc Console.WriteLine(); } -``` +``` + +We have written out some informations about the RECEIVED COINS using QBitNinja's GetTransactionResponse class and NBitcoins's Transaction class. + +**Exercise**: Write out the same information about the SPENT COINS using QBitNinja's GetTransactionResponse class! -Now let's examine the **inputs**. If you look at them you will notice a previous output is referenced. Each input shows you which previous out has been spent in order to fund this transaction. + +Now let's examine the **inputs**. If you look at them, you will notice a previous output is referenced. Each input shows you which previous out has been spent in order to fund this transaction. ```cs var inputs = transaction.Inputs; foreach (TxIn input in inputs) { OutPoint previousOutpoint = input.PrevOut; - Console.WriteLine(previousOutpoint.Hash); // hash of prev tx - Console.WriteLine(previousOutpoint.N); // idx of out from prev tx, that has been spent in the current tx - Console.WriteLine(); + //Get the hash of the previous transaction's OutPoint + Console.WriteLine(previousOutpoint.Hash); + //Get the index number of the previous transaction's OutPoint. + Console.WriteLine(previousOutpoint.N); } ``` @@ -116,7 +145,7 @@ Not to be confused with **OutPoint**, but more on this later. In summary, the TxOut represents an amount of bitcoin and a **ScriptPubKey**. (Recipient) ![](../assets/TxOut.png) -As illustration let's create a txout with 21 bitcoin from the first ScriptPubKey in our current transaction: +As the illustration let's create a TxOut with 21 bitcoins from the first ScriptPubKey in our current transaction: ```cs Money twentyOneBtc = new Money(21, MoneyUnit.BTC); @@ -132,8 +161,12 @@ For example, the **Outpoint** of the **TxOut** with 13.19683492 BTC in our trans ```cs OutPoint firstOutPoint = receivedCoins.First().Outpoint; -Console.WriteLine(firstOutPoint.Hash); // f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94 -Console.WriteLine(firstOutPoint.N); // 0 +Console.WriteLine(firstOutPoint.Hash); +//Output: +//f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94 +Console.WriteLine(firstOutPoint.N); +//Output: +//0 ``` Now let’s take a closer look at the inputs (aka **TxIn**) of the transaction: @@ -143,14 +176,18 @@ Now let’s take a closer look at the inputs (aka **TxIn**) of the transaction: The **TxIn** is composed of the **Outpoint** of the **TxOut** being spent and of the **ScriptSig** (we can see the ScriptSig as the “Proof of Ownership”). In our transaction there are actually 9 inputs. ```cs -Console.WriteLine(transaction.Inputs.Count); // 9 +Console.WriteLine(transaction.Inputs.Count); +//Output: +//9 ``` With the previous outpoint's transaction ID we can review the information associated with that transaction. ```cs OutPoint firstPreviousOutPoint = transaction.Inputs.First().PrevOut; var firstPreviousTransaction = client.GetTransaction(firstPreviousOutPoint.Hash).Result.Transaction; -Console.WriteLine(firstPreviousTransaction.IsCoinBase); // False +Console.WriteLine(firstPreviousTransaction.IsCoinBase); +//Output: +//False ``` We could continue to trace the transaction IDs back in this manner until we reach a **coinbase transaction**, the transaction including the newly mined coin by a miner. @@ -166,7 +203,9 @@ foreach (var spentCoin in spentCoins) { spentAmount = (Money)spentCoin.Amount.Add(spentAmount); } -Console.WriteLine(spentAmount.ToDecimal(MoneyUnit.BTC)); // 13.19703492 +Console.WriteLine(spentAmount.ToDecimal(MoneyUnit.BTC)); +//Output: +//13.19703492 ``` In this transaction 13.19**68**3492 BTC were received. @@ -180,5 +219,5 @@ var fee = transaction.GetFee(spentCoins.ToArray()); Console.WriteLine(fee); ``` -You should note that a **coinbase transaction** is the only transaction whose value of output are superior to the value of input. This effectively correspond to coin creation. So by definition there is no fee in a coinbase transaction. The coinbase transaction is the first transaction of every block. +You should note that a **coinbase transaction** is the only transaction whose value of output are superior to the value of input. This effectively corresponds to coin creation. So by definition there is no fee in a coinbase transaction. The coinbase transaction is the first transaction of every block. The consensus rules enforce that the sum of output's value in the coinbase transaction does not exceed the sum of transaction fees in the block plus the mining reward. diff --git a/key_generation/key_generation.md b/key_generation/key_generation.md index af0527a..5afdce5 100644 --- a/key_generation/key_generation.md +++ b/key_generation/key_generation.md @@ -10,11 +10,11 @@ On iOS, I have not implemented it and you will need to create your own **IRandom For a computer, being random is hard. But the biggest issue is that it is impossible to know if a series of numbers is really random. -If malware modifies your PRNG (and so, can predict the numbers you will generate), you won’t see it until it is too late. +If malware modifies your PRNG so that it can predict the numbers you will generate, you won’t see it until it is too late. It means that a cross platform and naïve implementation of PRNG (like using the computer’s clock combined with CPU speed) is dangerous. But you won’t see it until it is too late. -For performance reasons, most PRNG works the same way: a random number, called a **Seed**, is chosen, then a predictable formula generates the next number each time you ask for it. +For performance reasons, most PRNG works the same way: a random number which is called a **Seed** is chosen, then a predictable formula generates the next number each time you ask for it. The amount of randomness of the seed is defined by a measure we call **Entropy**, but the amount of **Entropy** also depends on the observer. @@ -26,24 +26,24 @@ If your attacker knows that you generated the key last week, then your seed has For such attacker, the entropy is log2(604800000) = 29.17 bits. -And enumerating such a number on my home computer took less than 2 seconds. We call such enumeration “brute forcing”. +And enumerating such all possibilities with corresponding entropy took less than 2 seconds on my home computer. We call such enumeration “brute forcing”. -However let’s say, you use the clock time + the process id for generating the seed. -Let’s imagine that there are 1024 different process ids. +However, let’s say, you use the clock time + the process ID for generating the seed. +Let’s imagine that there are 1024 different process IDs. So now, the attacker needs to enumerate 604800000 \* 1024 possibilities, which take around 2000 seconds. -Now, let’s add the time when I turned on my computer, assuming the attacker knows I turned it on today, it adds 86400000 possibilities. +Now, let’s add the time on it. When I turned on my computer, assuming the attacker knows I turned it on today, it adds 86400000 possibilities. Now the attacker needs to enumerate 604800000 \* 1024 \* 86400000 = 5,35088E+19 possibilities. However, keep in mind that if the attacker has infiltrated my computer, he can get this last piece of info, and bring down the number of possibilities, reducing entropy. Entropy is measured by **log2(possibilities)** and so log2(5,35088E+19) = 65 bits. -Is it enough? Probably, assuming your attacker does not know more information about the realm of possibilities used to generate the seed. +Is it enough? Probably, only when you assuming your attacker does not know more information about the realm of possibilities used to generate the seed. But since the hash of a public key is 20 bytes (160 bits), it is smaller than the total universe of the addresses. You might do better. -> **Note:** Adding entropy is linearly harder, cracking entropy is exponentially harder +> **Note:** Adding entropy is linearly harder. On the other hand, cracking entropy is exponentially harder. An interesting way of generating entropy quickly is by incorporating human intervention, such as moving the mouse. @@ -65,13 +65,13 @@ Then when you generate a new number: However, what is most important is not the number of possibilities. It is the time that an attacker would need to successfully break your key. That’s where KDF enters the game. -KDF, or **Key Derivation Function** is a way to have a stronger key, even if your entropy is low. +KDF, or **Key Derivation Function**, is a way to have a stronger key, even if your entropy is low. -Imagine that you want to generate a seed, and the attacker knows that there are 10.000.000 possibilities. +Imagine that you want to generate a seed, and the attacker knows that there are 10,000,000 possibilities. Such a seed would be normally cracked pretty easily. But what if you could make the enumeration slower? -A KDF is a hash function that waste computing resources on purpose. +A KDF is a hash function that wastes computing resources on purpose. Here is an example: ```cs @@ -79,13 +79,13 @@ var derived = SCrypt.BitcoinComputeDerivedKey("hello", new byte[] { 1, 2, 3 }); RandomUtils.AddEntropy(derived); ``` -Even if your attacker knows that your source of entropy is 5 letters, he will need to run Scrypt to check each possibility, which take 5 seconds on my computer. +Even if your attacker knows that your source of entropy is 5 letters, he will need to run Scrypt to check each possibility, which takes 5 seconds on my computer. The bottom line is: There is nothing paranoid in distrusting a PRNG, and you can mitigate an attack by both adding entropy and also using a KDF. Keep in mind that an attacker can decrease entropy by gathering information about you or your system. -If you use the timestamp as entropy source, then an attacker can decrease the entropy by knowing you generated the key last week, and that you only use your computer between 9am and 6pm. +If you use the timestamp as entropy source, then an attacker can decrease the entropy by knowing the fact that you generated the key last week, and that you only use your computer between 9am and 6pm. -In the previous part I talked briefly about a special KDF called **Scrypt.** As I said, the goal of a KDF is to make brute force costly. +In the previous part I talked briefly about a special KDF called **Scrypt.** As I said, the goal of a KDF is to make "brute forcing" costly. So it should be no surprise for you that a standard already exists for encrypting your private key with a password using a KDF. This is [BIP38](http://www.codeproject.com/Articles/775226/NBitcoin-Cryptography-Part). @@ -106,11 +106,11 @@ Console.ReadLine(); Such encryption is used in two different cases: * You do not trust your storage provider (they can get hacked) -* You are storing the key on the behalf of somebody else (and you do not want to know thier key) +* You are storing the key on the behalf of somebody else (and you do not want to know their key) If you own your storage, then encrypting at the database level might be enough. -Be careful if your server takes care of decrypting the key, an attacker might attempt to DDOS your server by forcing it to decrypt lots of keys. +Be careful if your server takes care of decrypting the key. An attacker might attempt a DDoS attack to your server by forcing it to decrypt lots of keys. Delegate decryption to the ultimate end user when you can. @@ -136,9 +136,9 @@ If you are developing a web wallet and generate keys on behalf of your users, an ## BIP38 (Part 2) {#bip38-part-2} -We already looked at using BIP38 to encrypt a key, however this BIP is in reality two ideas in one document. +We already looked at using BIP38 to encrypt a key. However, this BIP is in reality two ideas in one document. -The second part of the BIP, shows how you can delegate Key and Address creation to an untrusted peer. It will fix one of our concerns. +The second part of the BIP shows how you can delegate Key and Address creation to an untrusted peer. It will fix one of our concerns. **The idea is to generate a PassphraseCode to the key generator. With this PassphraseCode, they will be able to generate encrypted keys on your behalf, without knowing your password, nor any private key. ** @@ -164,21 +164,27 @@ The third party will then generate new encrypted keys for you. EncryptedKeyResult encryptedKeyResult = passphraseCode.GenerateEncryptedSecret(); ``` -This **EncryptedKeyResult** has lots of information: +This **EncryptedKeyResult** class has lots of information: ![](../assets/EncryptedKeyResult.png) -First: the **generated bitcoin address**, +First is the **generated bitcoin address**, ```cs -var generatedAddress = encryptedKeyResult.GeneratedAddress; // 14KZsAVLwafhttaykXxCZt95HqadPXuz73 +var generatedAddress = encryptedKeyResult.GeneratedAddress; +//Output: +//14KZsAVLwafhttaykXxCZt95HqadPXuz73 ``` -then the **EncryptedKey** itself, (as we have seen in the previous, **Key Encryption** lesson), +Second is the **EncryptedKey** itself as we have seen in the previous, **Key Encryption** lesson. ```cs -var encryptedKey = encryptedKeyResult.EncryptedKey; // 6PnWtBokjVKMjuSQit1h1Ph6rLMSFz2n4u3bjPJH1JMcp1WHqVSfr5ebNS +var encryptedKey = encryptedKeyResult.EncryptedKey; +//Output: +//6PnWtBokjVKMjuSQit1h1Ph6rLMSFz2n4u3bjPJH1JMcp1WHqVSfr5ebNS ``` -and last but not least, the **ConfirmationCode**, so that the third party can prove that the generated key and address correspond to your password. +And last but not least, the **ConfirmationCode**, so that the third party can prove that the generated key and address correspond to my password. ```cs -var confirmationCode = encryptedKeyResult.ConfirmationCode; // cfrm38VUcrdt2zf1dCgf4e8gPNJJxnhJSdxYg6STRAEs7QuAuLJmT5W7uNqj88hzh9bBnU9GFkN +var confirmationCode = encryptedKeyResult.ConfirmationCode; +//Output: +//cfrm38VUcrdt2zf1dCgf4e8gPNJJxnhJSdxYg6STRAEs7QuAuLJmT5W7uNqj88hzh9bBnU9GFkN ``` As the owner, once you receive this information, you need to check that the key generator did not cheat by using **ConfirmationCode.Check**, then get your private key with your password: @@ -190,7 +196,8 @@ Console.WriteLine(bitcoinPrivateKey.GetAddress() == generatedAddress); // True Console.WriteLine(bitcoinPrivateKey); // KzzHhrkr39a7upeqHzYNNeJuaf1SVDBpxdFDuMvFKbFhcBytDF1R ``` -So, we have just seen how the third party can generate encrypted keys on your behalf, without knowing your password and private key. +So, we have just seen how the third party can generate encrypted keys on your behalf, without them knowing your password and private key. +In other words, you've delegated a Key and Address generation to an untrusted peer, the third party. ![](../assets/ThirdPartyKeyGeneration.png) @@ -198,7 +205,7 @@ However, one problem remains: * All backups of your wallet that you have will become outdated when you generate a new key. -BIP 32, or Hierarchical Deterministic Wallets (HD wallets) proposes another solution, which is more widely supported. +BIP 32, or Hierarchical Deterministic Wallets (HD wallets), proposes another solution which is more widely supported. ## HD Wallet (BIP 32) {#hd-wallet-bip-32} @@ -210,7 +217,7 @@ Let’s keep in mind the problems that we want to resolve: A “Deterministic” wallet would fix our backup problem. With such a wallet, you would have to save only the seed. From this seed, you can generate the same series of private keys over and over. This is what the “Deterministic” stands for. -As you can see, from the master key, I can generate new keys: +As you can see below the codes, from a master key, I can generate new keys which are derived child keys from the master key: ```cs ExtKey masterKey = new ExtKey(); @@ -234,7 +241,7 @@ Key 5 : xprv9tvBA4Kt8UTuTdiEhN8iVDr5rfAPSVsCKpDia4GtEsb87eHr8yRVveRhkeLEMvo3XWL3 You only need to save the **masterKey**, since you can generate the same suite of private keys over and over. -As you can see, these keys are **ExtKey** and not **Key** as you are used to. However, this should not stop you since you have the real private key inside: +As you can see, these keys are **ExtKey** and not **Key** as you are used to. However, this should not stop you since you have a real private key inside of these keys: ![](../assets/ExtKey.png) @@ -243,19 +250,22 @@ You can go back from a **Key** to an **ExtKey** by supplying the **Key** and the ```cs ExtKey extKey = new ExtKey(); byte[] chainCode = extKey.ChainCode; -Key key = extKey.PrivateKey; - -ExtKey newExtKey = new ExtKey(key, chainCode); +Key privateKeyFromExtKey = extKey.PrivateKey; +//Supply a private key and a chain code to the ExtKey constructor to go back from a Key to an ExtKey. +ExtKey newExtKey = new ExtKey(privateKeyFromExtKey, chainCode); ``` -The **base58** type equivalent of **ExtKey** is called **BitcoinExtKey**. +The **Base58** type equivalent of **ExtKey** is called **BitcoinExtKey**. -But how can we solve our second problem: delegating address creation to a peer that can potentially be hacked (like a payment server)? +But how can we solve our second problem: Delegating key/address creation process to an untrusted peer that can potentially be hacked like a payment server? The trick is that you can “neuter” your master key, then you have a public (without private key) version of the master key. From this neutered version, a third party can generate public keys without knowing the private key. ```cs +//Neuter the master key, then you get a master public key. ExtPubKey masterPubKey = masterKey.Neuter(); + +//Genarate 5 derived public keys from the master public key. for (int i = 0 ; i < 5 ; i++) { ExtPubKey pubkey = masterPubKey.Derive((uint)i); @@ -271,19 +281,19 @@ PubKey 3 : xpub67uQd5a6WCY6HQKya2Mwwb7bpSNB5XhWCR76kRaPxchE3Y1Y2MAiSjhRGftmeWyX8 PubKey 4 : xpub67uQd5a6WCY6JddPfiPKdrR49KYEuXUwwJJsL5rWGDDQkpPctdkrwMhXgQ2zWopsSV7buz61e5mGSYgDisqA3D5vyvMtKYP8S3EiBn5c1u4 ``` -So imagine that your payment server generates pubkey1, you can get the corresponding private key with your private master key. +So imagine that your payment server generates pubkey1, and then you can get the corresponding private key by your private master key. ```cs masterKey = new ExtKey(); masterPubKey = masterKey.Neuter(); -//The payment server generate pubkey1 +//The payment server generates the pubkey1. ExtPubKey pubkey1 = masterPubKey.Derive((uint)1); -//You get the private key of pubkey1 +//You get the private key of pubkey1. ExtKey key1 = masterKey.Derive((uint)1); -//Check it is legit +//Check if it is legit. Console.WriteLine("Generated address : " + pubkey1.PubKey.GetAddress(Network.Main)); Console.WriteLine("Expected address : " + key1.PrivateKey.PubKey.GetAddress(Network.Main)); ``` @@ -297,11 +307,13 @@ Expected address : 1Jy8nALZNqpf4rFN9TWG2qXapZUBvquFfX ![](../assets/ExtPubKey.png) -Now we have seen how Deterministic keys solve our problems, let’s speak about what the “hierarchical” is for. +Now that we have seen how Deterministic keys solve our problems, let’s speak about what the “Hierarchical” is for. -In the previous exercise, we have seen that by combining master key + index we could generate another key. We call this process **Derivation**, the master key is the **parent key**, and any generated keys are called **child keys**. +In the previous exercise, we have seen that we could generate another derived keys based on a master key by invoking Derive() method on the master key passing integer numbers into an argument. -However, you can also derivate children from the child key. This is what the “hierarchical” stands for. +We call this process a **Derivation**. And, in this scheme, a master key is a **parent key**, and any generated keys based on the master key are called **child keys**. + +However, you can also derivate children from the child key. This is what the “Hierarchical” stands for. This is why conceptually more generally you can say: Parent Key + KeyPath => Child Key @@ -328,32 +340,31 @@ So in summary: ![](../assets/DeriveKeyPath.png) -It works the same for **ExtPubKey**. +It works indentically for **ExtPubKey**. -Why do you need hierarchical keys? Because it might be a nice way to classify the type of your keys for multiple accounts. More on [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki). +Why do you need hierarchical keys? It's because it might be a nice way to classify the type of your keys for multiple accounts. More on [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki). It also permits segmenting account rights across an organization. -Imagine you are CEO of a company. You want control over all wallets, but you don’t want the Accounting department to spend the money from the Marketing department. +Imagine you are the CEO of a company. You want control over all wallets, but you don’t want the Accounting department to spend the money from the Marketing department. -So your first idea would be to generate one hierarchy for each department. +So, for implementing this constraint, your first idea would be to generate one hierarchy for each department. ![](../assets/CeoMarketingAccounting.png) -However, in such a case, **Accounting** and **Marketing** would be able to recover the CEO’s private key. - -We define such child keys as **non-hardened**. +However, in such a case, **Accounting** and **Marketing** would be able to recover the CEO’s private key, because we defined such child keys as **non-hardened**. ![](../assets/NonHardened.png) ```cs ExtKey ceoKey = new ExtKey(); Console.WriteLine("CEO: " + ceoKey.ToString(Network.Main)); +//Note the hardened is false. ExtKey accountingKey = ceoKey.Derive(0, hardened: false); ExtPubKey ceoPubkey = ceoKey.Neuter(); -//Recover ceo key with accounting private key and ceo public key +//Recover the CEO key with accounting private key and CEO public key. ExtKey ceoKeyRecovered = accountingKey.GetParentExtKey(ceoPubkey); Console.WriteLine("CEO recovered: " + ceoKeyRecovered.ToString(Network.Main)); ``` @@ -363,9 +374,9 @@ CEO: xprv9s21ZrQH143K2XcJU89thgkBehaMqvcj4A6JFxwPs6ZzGYHYT8dTchd87TC4NHSwvDuexuF CEO recovered: xprv9s21ZrQH143K2XcJU89thgkBehaMqvcj4A6JFxwPs6ZzGYHYT8dTchd87TC4NHSwvDuexuFVFpYaAt3gztYtZyXmy2hCVyVyxumdxfDBpoC ``` -In other words, a **non-hardened key** can “climb” the hierarchy. **Non-hardened keys** should only be used for categorizing accounts that belongs to a point of **single control**. +In other words, a **non-hardened key** can “climb” the hierarchy. **Non-hardened keys** should only be used for categorizing accounts that belong to a point of **single control**. -So in our case, the CEO should create a **hardened key**, so the accounting department will not be able to climb the hierarchy. +So, in our case, the CEO should create child keys as **hardened** ones, so the accounting department will not be able to climb the hierarchy. ```cs ExtKey ceoKey = new ExtKey(); @@ -424,7 +435,8 @@ mnemo = new Mnemonic("minute put grant neglect anxiety case globe win famous cor hdRoot = mnemo.DeriveExtKey("my password"); ``` -Currently supported languages for **wordlist** are, English, Japanese, Spanish, Chinese (simplified and traditional). +Currently supported languages for wordlist are English, Japanese, Korean, Spanish, Chinese (simplified and traditional), French, Italian. +Check [here](https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md). ## Dark Wallet {#dark-wallet} diff --git a/other_types_of_asset/colored_coins.md b/other_types_of_asset/colored_coins.md index 5a14979..4b31ebb 100644 --- a/other_types_of_asset/colored_coins.md +++ b/other_types_of_asset/colored_coins.md @@ -1,34 +1,35 @@ -## Colored Coins {#colored-coins} +## Chapter1. Colored Coins {#colored-coins} -So until now, you have seen how to exchange Bitcoins on the network. However you can use the Bitcoin network for transferring and exchanging any type of assets. +So until now, you have seen how to exchange Bitcoins on the network. However, you can use the Bitcoin network for transferring and exchanging any type of assets. We call such assets “colored coins”. As far as the Blockchain is concerned, there is no difference between a Coin and a Colored Coin. -A colored coin is represented by a standard **TxOut**. Most of the time, such **TxOut** have a residual Bitcoin value called “Dust”. (600 satoshi) +A colored coin is represented by a standard **TxOut**. Most of the time, such **TxOut** has a residual Bitcoin value called “Dust” (600 satoshi). And for a reference, "Dust" in the Blockchain system means the amount of coin value which is smaller than the transaction fee. -The real value of a colored coin reside in what the **issuer** of the coin will exchange against it. +The real value of a colored coin resides in what the **issuer** of the coin will exchange against it. ![](../assets/ColoredCoin.png) -Since a colored coin is nothing but a standard coin with special meaning, it follows that all what you saw about proof of ownership and the **TransactionBuilder** stays true. You can transfer a colored coin with exactly the same rules as before. +Since a colored coin is nothing but a standard coin with a special meaning, it follows all rules and protocols what you saw about proof of ownership and the feature of the **TransactionBuilder** also stays true. You can transfer a colored coin by exactly the same rules as we did before. As far as the blockchain is concerned, a **Colored Coin** is a **Coin** like all others. -You can represent several type of asset with a colored coin: company shares, bonds, stocks, votes. +You can represent several types of asset by a colored coin: company shares, bonds, stocks, and votes etc. -But no matter what type of asset you will represent, there will always have a trust relationship between the **issuer** of the asset and the **owner**. +But no matter what types of asset you will represent, there will always have a trust relationship between the **issuer** of the asset and the **owner**. If you own some company share, then the company might decide to not send you dividends. If you own a bond, then the bank might not exchange it at maturity. However, a violation of contract might be automatically detected with the help of **Ricardian Contracts**. -A **Ricardian Contract** is a contract signed by the issuer with the rights attached to the asset. Such contract can be either human readable (pdf), but also structured (json), so tools can automatically prove any violation. +A **Ricardian Contract** is a contract signed by the issuer with the rights attached to the asset. Such contract can be either human readable (PDF) or structured (JSON), so that tools can automatically prove any violation. + The **issuer** can’t change the **ricardian contract** attached to an asset. The Blockchain is only the transport medium of a financial instrument. The innovation is that everyone can create and transfer its own asset without intermediary, whereas traditional asset transport medium (clearing houses), are either heavily regulated, or purposefully kept secret, and closed to the general public. -**Open Asset** is the name of the protocol created by Flavien Charlon that describes how to **transfer** and **emit** colored coins on the Blockchain. -Other protocols exist, but Open Asset is the most easy and flexible and the only one supported by **NBitcoin**. +**Open Asset** is the name of the protocol created by Flavien Charlon who describes how to **transfer** and **emit** colored coins on the Blockchain. +Other protocols also exist, but Open Asset is the most easy and flexible and the only one supported by **NBitcoin**. -In the rest of the book, I will not go in the details of the Open Asset protocol, the GitHub page of the specification is better suited to this need. \ No newline at end of file +In the rest of the book, I will not go in the details of the Open Asset protocol. The GitHub page of the specification for Open Asset protocol would be better suited to this need. diff --git a/other_types_of_asset/issuing_an_asset.md b/other_types_of_asset/issuing_an_asset.md index e62756a..724505c 100644 --- a/other_types_of_asset/issuing_an_asset.md +++ b/other_types_of_asset/issuing_an_asset.md @@ -1,24 +1,24 @@ -## Issuing an Asset {#issuing-an-asset} +## Chapter2. Issuing an Asset {#issuing-an-asset} -### Objective {#objective} +### Section1. Objective {#objective} For the purpose of this exercise, I will emit **BlockchainProgramming coins**. -You get **one of these BlockchainProgramming coins** for every **0.004 bitcoin** you send me. -**One more** if you add some kind words. -Furthermore this is a great opportunity to make it to the [Hall of The Makers](http://n.bitcoin.ninja/). +You'll get **one of these BlockchainProgramming coins** for every **0.004 bitcoins** you send me. +**One more**, if you add some kind words. +Furthermore, this is a great opportunity to make it to the [Hall of The Makers](http://n.bitcoin.ninja/). Let’s see how I would code such feature. -### Issuance Coin {#issuance-coin} +### Section2. Issuance Coin {#issuance-coin} In Open Asset, the Asset ID is derived from the issuer's **ScriptPubKey**. If you want to issue a Colored Coin, you need to prove ownership of such **ScriptPubKey**. And the only way to do that on the Blockchain is by spending a coin belonging to such **ScriptPubKey**. The coin that you will choose to spend for issuing colored coins is called “**Issuance Coin**” in **NBitcoin**. -I want to emit an Asset from the book bitcoin address: [1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB](https://www.smartbit.com.au/address/1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB). +I want to emit an Asset from the Bitcoin address for this book: [1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB](https://www.smartbit.com.au/address/1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB). -Take a look at my balance, I decided to use the following coin for issuing assets. +Take a look at my balance. I decided to use the following coin (2,000,000 satoshis) as Issuance Coin for issuing assets. ```json { @@ -42,7 +42,7 @@ var coin = new Coin( var issuance = new IssuanceCoin(coin); ``` -Now I need to build transaction and sign the transaction with the help of the **TransactionBuilder**. +Now I need to build a transaction and sign the transaction with the help of the **TransactionBuilder**. ```cs var nico = BitcoinAddress.Create("15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe"); @@ -86,10 +86,10 @@ Here is the format of the data in the OP_RETURN. ![](../assets/ColorMaker.png) -In our case, Quantities have only 10, which is the number of Asset I issued to ```nico```. Metadata is arbitrary data. We will see that we can put an url that points to an “Asset Definition”. -An **Asset Definition** is a document that describes what the Asset is. It is optional, we are not using it in our case. (We’ll come back later on it in the Ricardian Contract part.) +In our case, Quantities have only 10 which is the number of Asset I issued to **nico**. Metadata is arbitrary data. We will see that we can put a URL that points to an “Asset Definition”. +An **Asset Definition** is a document that describes what the Asset is. Since it is optional, we are not using it in our case. We’ll come back later on it in the Ricardian Contract part. -For more information check out the [Open Asset Specification](https://github.com/OpenAssets/open-assets-protocol/blob/master/specification.mediawiki). +For more information, check out the [Open Asset Specification](https://github.com/OpenAssets/open-assets-protocol/blob/master/specification.mediawiki). After transaction verifications it is ready to be sent to the network. @@ -126,17 +126,16 @@ using (var node = Node.ConnectToLocal(Network.Main)) //Connect to the node Thread.Sleep(500); //Wait a bit } ``` - -My Bitcoin Wallet have both, the book address and the “Nico” address. +My Bitcoin Wallet has both, the Bitcoin address for this book and “Nico”. ![](../assets/NicoWallet.png) -As you can see, Bitcoin Core only shows the 0.0001 BTC of fees I paid, and ignore the 600 Satoshi coin because of spam prevention feature. +As you can see, Bitcoin Core only shows the 0.0001 BTC of fees I paid, and ignores the 600 Satoshi coins because of a spam prevention feature. This classical bitcoin wallet knows nothing about Colored Coins. -Worse: If a classical bitcoin wallet spend a colored coin, it will destroy the underlying asset and transfer only the bitcoin value of the **TxOut**. (600 satoshi) +Worse: If a classical bitcoin wallet spends a colored coin, it will destroy the underlying asset and transfer only the bitcoin value of the **TxOut**. (600 satoshi) -For preventing a user from sending Colored Coin to a wallet that do not support it, Open Asset have its own address format, that only colored coin wallets understand. +For preventing a user from sending Colored Coin to a wallet which does not support it, Open Asset has its own address format which only colored coin wallets understand. ```cs nico = BitcoinAddress.Create("15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe"); @@ -147,11 +146,11 @@ Console.WriteLine(nico.ToColoredAddress()); akFqRqfdmAaXfPDmvQZVpcAQnQZmqrx4gcZ ``` -Now, you can take a look on an Open Asset compatible wallet like Coinprism, and see my asset correctly detected: +Now, you can take a look at on an Open Asset compatible wallet like Coinprism, and see if my asset is correctly detected: ![](../assets/Coinprism.png) -As I have told you before, the Asset ID is derived from the issuer’s **ScriptPubKey**, here is how to get it in code: +As I have told you before, the Asset ID is derived from the issuer’s ScriptPubKey. Here is how to get it in code: ```cs var book = BitcoinAddress.Create("1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB"); diff --git a/other_types_of_ownership/arbitrary.md b/other_types_of_ownership/arbitrary.md index 0921f2b..f17dd7b 100644 --- a/other_types_of_ownership/arbitrary.md +++ b/other_types_of_ownership/arbitrary.md @@ -2,55 +2,64 @@ From Bitcoin 0.10, the **RedeemScript** can be arbitrary, which means that with the script language of Bitcoin, you can create your own definition of what “ownership” means. -For example, I can give money to whoever knows either my date of birth (dd/mm/yyyy) serialized in UTF-8 or the private key of **1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB**. -The details of the script language are out of scope. You can easily find the documentation on various websites. The Bitcoin script language is a stack based language so everyone having done some assembler should be able to read it. +For example, in this scheme, imagine I send the coins to the Bitcoin address of this book, **1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB**, with adding an arbitrary redeem ScriptPubKey containing custum scripts which partially contain the hash value of my birth date. And whoever either knows "my date of birth" in the format of "dd/mm/yyyy", serialized in UTF-8 or the "private key" related to the Bitcoin address of this book can spend the coins by prooving the ownership for that one. + +The details of the script language are out of scope of this book. You can easily find the documentation for the Bitcoin script language on various websites. And since it is a stack based language so everyone having done with some assembler should be able to read it. + > **Note:** ([nopara73](https://github.com/nopara73)) I find [Davide De Rosa's tutorial](http://davidederosa.com/basic-blockchain-programming/bitcoin-script-language-part-one/) as the most enjoyable one. So first, let’s build the **RedeemScript**, -> **Note:** For this code to work right click **References** ->** Add Reference...** -> Find **System.Numerics** +> **Note:** For this code to work right, Click **References** -> **Add Reference** -> Find **System.Numerics** ```cs -BitcoinAddress address = BitcoinAddress.Create("1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB"); -var birth = Encoding.UTF8.GetBytes("18/07/1988"); -var birthHash = Hashes.Hash256(birth); +BitcoinAddress bitcoinAddressOfThisBook = BitcoinAddress.Create("1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB"); +var birthDate = Encoding.UTF8.GetBytes("18/07/1988"); +var birthDateHash = Hashes.Hash256(birthDate); Script redeemScript = new Script( - "OP_IF " - + "OP_HASH256 " + Op.GetPushOp(birthHash.ToBytes()) + " OP_EQUAL " + - "OP_ELSE " - + address.ScriptPubKey + " " + - "OP_ENDIF"); + "OP_IF " + + "OP_HASH256 " + Op.GetPushOp(birthDateHash.ToBytes()) + " OP_EQUAL " + + "OP_ELSE " + + address.ScriptPubKey + " " + + "OP_ENDIF"); ``` -This **RedeemScript** means that there are 2 ways of spending such **ScriptCoin**: Either you know the data that gives **birthHash** (my birthdate) or you own the bitcoin address. -Let’s say I sent money to such **redeemScript**: +This **RedeemScript** means that there are 2 ways of spending such **ScriptCoin**: It can be spent by anyone in either case he knows the data(birthDate) that can generate birthDateHash, or knows the private key related to the Bitcoin address of this book. + + +Let’s say I sent money with such **redeemScriptPubKeyForSendingCoinToBook**: ```cs -var tx = new Transaction(); -tx.Outputs.Add(new TxOut(Money.Parse("0.0001"), redeemScript.Hash)); -ScriptCoin scriptCoin = tx.Outputs.AsCoins().First().ToScriptCoin(redeemScript); +var txForSendingCoinToBook = new Transaction(); +txForSendingCoinToBook.Outputs.Add(new TxOut(Money.Parse("0.0001"), redeemScriptPubKeyForSendingCoinToBook.Hash)); +ScriptCoin scriptCoinForSendingToBook = txForSendingCoinToBook + .Outputs + .AsCoins() + .First() + .ToScriptCoin(redeemScriptPubKeyForSendingCoinToBook); ``` So let’s create a transaction that wants to spend such output: ```cs -//Create spending transaction -Transaction spending = new Transaction(); -spending.AddInput(new TxIn(new OutPoint(tx, 0))); +//Create spending transaction. +Transaction txSpendingCoinOfThisBook = new Transaction(); +txSpendingCoinOfThisBook.AddInput(new TxIn(new OutPoint(txForSendingCoinToBook, 0))); ``` -The first option is to know my birth date and to prove it in the **scriptSig**: +The first option for any spender to spend the coin is to know my birth date to prove the ownership for the coin by interacting with the scriptSig. ```cs -////Option 1 : Spender knows my birthdate -Op pushBirthdate = Op.GetPushOp(birth); -Op selectIf = OpcodeType.OP_1; //go to if -Op redeemBytes = Op.GetPushOp(redeemScript.ToBytes()); +//Option 1 : Spender knows my birth date. +Op pushBirthdate = Op.GetPushOp(birthDate); +//Go to IF. +Op selectIf = OpcodeType.OP_1; +Op redeemBytes = Op.GetPushOp(redeemScriptPubKeyForSendingCoinToBook.ToBytes()); Script scriptSig = new Script(pushBirthdate, selectIf, redeemBytes); -spending.Inputs[0].ScriptSig = scriptSig; +txSpendingCoinOfThisBook.Inputs[0].ScriptSig = scriptSig; ``` You can see that in the **scriptSig** I push **OP_1** so I enter in the **OP_IF** of my **RedeemScript**. @@ -58,38 +67,43 @@ Since there is no backed-in template, for creating such **scriptSig**, you can s Then you can check that the **scriptSig** proves the ownership of the **scriptPubKey**: + ```cs //Verify the script pass -var result = spending +var verificationByBirthDate = txSpendingCoinOfThisBook .Inputs .AsIndexedInputs() .First() - .VerifyScript(tx.Outputs[0].ScriptPubKey); -Console.WriteLine(result); // True + .VerifyScript(txForSendingCoinToBook.Outputs[0].ScriptPubKey); +Console.WriteLine(result); +//Output: +//True ``` -The second way of spending the coin is by proving ownership of **1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB**. +The second way for some spender to spend the coin is by proving ownership of the Bitcoin address, **1KF8kUVHK42XzgcmJF4Lxz4wcL5WDL97PB**, by corresponding the private key. ``` -////Option 2 : Spender knows my private key -BitcoinSecret secret = new BitcoinSecret("..."); -var sig = spending.SignInput(secret, scriptCoin); +//Option 2 : Spender knows my private key. +BitcoinSecret secret = new BitcoinSecret("PrivateKeyRepresentedInBase58StringRelatedToTheBookBitcoinAddress"); +var sig = txSpendingCoinOfThisBook.SignInput(privateKeyRelatedToTheBookBitcoinAddress, scriptCoinForSendingToBook); var p2pkhProof = PayToPubkeyHashTemplate .Instance - .GenerateScriptSig(sig, secret.PrivateKey.PubKey); -selectIf = OpcodeType.OP_0; //go to else + .GenerateScriptSig(sig, privateKeyRelatedToTheBookBitcoinAddress.PrivateKey.PubKey); +//Go to IF. +selectIf = OpcodeType.OP_0; scriptSig = p2pkhProof + selectIf + redeemBytes; -spending.Inputs[0].ScriptSig = scriptSig; +txSpendingCoinOfThisBook.Inputs[0].ScriptSig = scriptSig; ``` And ownership is also proven: ```cs //Verify the script pass -result = spending +var verificationByPrivateKey = txSpendingCoinOfThisBook .Inputs .AsIndexedInputs() .First() - .VerifyScript(tx.Outputs[0].ScriptPubKey); -Console.WriteLine(result); // True -/////////// + .VerifyScript(txForSendingCoinToBook.Outputs[0].ScriptPubKey); +Console.WriteLine(verificationByPrivateKey); +//Output: +//True ``` diff --git a/other_types_of_ownership/multi_sig.md b/other_types_of_ownership/multi_sig.md index 810960c..cfe15bf 100644 --- a/other_types_of_ownership/multi_sig.md +++ b/other_types_of_ownership/multi_sig.md @@ -116,11 +116,12 @@ Console.WriteLine(fullySigned); } ] } - ``` -Before sending the transaction to the network, examine the need of CombineSignatures() method. Try to compare a full detail of transaction between bobSigned and fullySigned. It will seem both are identical. For this reason, it seems like the CombineSignatures() method is needless because mulit-signing has achieved without the CombineSignatures() method. + +Before sending the transaction to the network, examine the need of CombineSignatures() method. Try to compare a full detail of transaction between bobSigned and fullySigned. It will seem both are identical. For this reason, it seems like the CombineSignatures() method is needless because mulit-sig has achieved without the CombineSignatures() method. Let's look at the case that CombineSignatures() is required: + ```cs TransactionBuilder builderNew = new TransactionBuilder(); TransactionBuilder builderForAlice = new TransactionBuilder(); @@ -133,13 +134,13 @@ Transaction unsignedNew = .BuildTransaction(sign: false); - Transaction aliceSigned = +Transaction aliceSigned = builderForAlice .AddCoins(coin) .AddKeys(alice) .SignTransaction(unsignedNew); - Transaction bobSigned = +Transaction bobSigned = builderForBob .AddCoins(coin) .AddKeys(bob) diff --git a/other_types_of_ownership/p2pk[h]_pay_to_public_key_[hash].md b/other_types_of_ownership/p2pk[h]_pay_to_public_key_[hash].md index 9a98475..40b5f0c 100644 --- a/other_types_of_ownership/p2pk[h]_pay_to_public_key_[hash].md +++ b/other_types_of_ownership/p2pk[h]_pay_to_public_key_[hash].md @@ -1,23 +1,29 @@ ## P2PK[H] \(Pay to Public Key [Hash]\) {#p2pk-h-pay-to-public-key-hash} ### P2PKH - Quick recap -We learned that a **Bitcoin Address** was the **hash of a** **public key**: +We learned that a **Bitcoin address** is generated by a **public key hash** and a **network identifier**. ```cs var publicKeyHash = new Key().PubKey.Hash; var bitcoinAddress = publicKeyHash.GetAddress(Network.Main); -Console.WriteLine(publicKeyHash); // 41e0d7ab8af1ba5452b824116a31357dc931cf28 -Console.WriteLine(bitcoinAddress); // 171LGoEKyVzgQstGwnTHVh3TFTgo5PsqiY +Console.WriteLine(publicKeyHash); +//Output +//41e0d7ab8af1ba5452b824116a31357dc931cf28 +Console.WriteLine(bitcoinAddress); +//Output +//171LGoEKyVzgQstGwnTHVh3TFTgo5PsqiY ``` -We also learned that as far as the blockchain is concerned, there is no such thing as a **bitcoin address**. The blockchain identifies a receiver with a **ScriptPubKey**, and that a **ScriptPubKey** could be generated from the address: +We also learned that as far as the blockchain is concerned, there is no such thing as a **bitcoin address**. The Blockchain identifies a receiver by a **ScriptPubKey**. And such **ScriptPubKey** could be generated from a Bitcoin address. ```cs var scriptPubKey = bitcoinAddress.ScriptPubKey; -Console.WriteLine(scriptPubKey); // OP_DUP OP_HASH160 41e0d7ab8af1ba5452b824116a31357dc931cf28 OP_EQUALVERIFY OP_CHECKSIG +Console.WriteLine(scriptPubKey); +//Output +//OP_DUP OP_HASH160 41e0d7ab8af1ba5452b824116a31357dc931cf28 OP_EQUALVERIFY OP_CHECKSIG ``` -And vice versa: +And vice versa. a Bitcoin address could be generated from a ScriptPubKey, but along with a network identifier. ```cs var sameBitcoinAddress = scriptPubKey.GetDestinationAddress(Network.Main); @@ -25,7 +31,7 @@ var sameBitcoinAddress = scriptPubKey.GetDestinationAddress(Network.Main); ### P2PK -However, not all **ScriptPubKey** represent a Bitcoin Address. For example the first transaction in the first ever blockchain block, called the genesis block: +However, not all **ScriptPubKey** represents a Bitcoin address. For example, the ScriptPubKey in the first transaction in the first ever blockchain block called the genesis block doesn't represent a Bitcoin address. In other words, the first ScriptPubKey ever in the genesis block represents null as a Bitcoin address. ```cs Block genesisBlock = Network.Main.GetGenesis(); @@ -33,7 +39,9 @@ Transaction firstTransactionEver = genesisBlock.Transactions.First(); var firstOutputEver = firstTransactionEver.Outputs.First(); var firstScriptPubKeyEver = firstOutputEver.ScriptPubKey; var firstBitcoinAddressEver = firstScriptPubKeyEver.GetDestinationAddress(Network.Main); -Console.WriteLine(firstBitcoinAddressEver == null); // True +Console.WriteLine(firstBitcoinAddressEver == null); +//Output +//True ``` ```cs @@ -52,24 +60,30 @@ Console.WriteLine(firstTransactionEver); } ``` -You can see that the form of the **scriptPubKey** is different: +You can see that the form of the **ScriptPubKey** is different: ```cs -Console.WriteLine(firstScriptPubKeyEver); // 04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f OP_CHECKSIG +Console.WriteLine(firstScriptPubKeyEver); +//Output +//04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f OP_CHECKSIG ``` -A bitcoin address is represented by: **OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG** +A Bitcoin address is represented by: +**OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG** -But here we have: **<pubkey> OP_CHECKSIG** +But here we have: +**<pubkey> OP_CHECKSIG** -In fact, at the beginning, **public key**s were used directly in the **ScriptPubKey**. +In fact, it's because, at the beginning, **public key**s were used directly in the **ScriptPubKey**. ```cs var firstPubKeyEver = firstScriptPubKeyEver.GetDestinationPublicKeys().First(); -Console.WriteLine(firstPubKeyEver); // 04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f +Console.WriteLine(firstPubKeyEver); +//Output: //04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f ``` Now we are mainly using the hash of the public key. +Examine how each P2PK and P2PKH works with a private key, a public key, a public key hash, and a ScriptPubKey. ![](../assets/PPKH.png) @@ -85,17 +99,17 @@ Pay to public key : 02fb8021bc7dedcc2f89a67e75cee81fedb8e41d6bfa6769362132544dfd Pay to public key hash : OP_DUP OP_HASH160 0ae54d4cec828b722d8727cb70f4a6b0a88207b2 OP_EQUALVERIFY OP_CHECKSIG ``` -These 2 types of payment are referred as **P2PK** (pay to public key) and **P2PKH** (pay to public key hash). +These 2 types of payment are referred as **P2PK** (Pay To Public Key) and **P2PKH** (Pay To Public Key Hash). Satoshi later decided to use P2PKH instead of P2PK for two reasons: -* Elliptic Curve Cryptography (the cryptography used by your **public key** and **private key**) is vulnerable to a modified Shor's algorithm for solving the discrete logarithm problem on elliptic curves. In plain English, it means that in the future a quantum computer might be able to **retrieve a private key from a public key**. By publishing the public key only when the coins are spent (and assuming that addresses are not reused), such an attack is rendered ineffective. +* Elliptic Curve Cryptography, the cryptography used by your **public key** and **private key**, is vulnerable to a modified Shor's algorithm for solving the discrete logarithm problem on elliptic curves. In plain English, it means that in the future a quantum computer might be able to **retrieve a private key from a public key**. By publishing the public key only when the coins are spent (and assuming that addresses are not reused), such an attack is rendered ineffective. * With the hash being smaller (20 bytes) it is easier to print and easier to embed into small storage mediums like QR codes. -Nowadays, there is no reason to use P2PK directly although it is still used in combination with P2SH... more on this later. +Nowadays, there is no reason to use a P2PK directly although it is still used in combination with a P2SH... And more on this later. -> ([Discussion](https://www.reddit.com/r/Bitcoin/comments/4isxjr/petition_to_protect_satoshis_coins/d30we6f)) If the issue of the early use of P2PK is not addressed it will have a serious impact on the Bitcoin price. +> ([Discussion](https://www.reddit.com/r/Bitcoin/comments/4isxjr/petition_to_protect_satoshis_coins/d30we6f)) If the issue of the early use of P2PK is not addressed, it will have a serious impact on the Bitcoin price. ### Exercise -([nopara73](https://github.com/nopara73)) While reading this chapter I found the the abbreviations (P2PK, P2PKH, P2W, etc..) very confusing. +([nopara73](https://github.com/nopara73)) While reading this chapter I found the abbreviations (P2PK, P2PKH, P2W*, etc..) very confusing. My trick was to force myself to pronounce the terms fully every time I encountered them during the following lessons. Suddenly everything made much more sense. I recommend you to do the same.