mirror of
https://github.com/bitcoinbook/bitcoinbook
synced 2024-11-12 19:08:56 +00:00
Merge branch 'develop' with libbitcoin and bx updates, misc edits and typo fixes
This commit is contained in:
commit
733bde3e65
13
README.md
13
README.md
@ -2,12 +2,15 @@
|
||||
|
||||
Mastering Bitcoin is a book for developers, but the first two chapters cover bitcoin at a level that is approachable to non-programmers. Anyone with a basic understanding of technology can read the first two chapters and get a great understanding of bitcoin.
|
||||
|
||||
# Contributing
|
||||
# Published
|
||||
|
||||
To contribute to this book, please fork and make changes to your forked copy, then submit a pull request. Or alternatively, if you cannot use the github.com pull request system, submit an Issue from the menu on the right. Major contributions will receive an acknowledgment in the preface of the book.
|
||||
"Mastering Bitcoin" is now available in print and e-book formats by many book sellers including [Amazon](http://www.amazon.com/Mastering-Bitcoin-Unlocking-Digital-Crypto-Currencies/dp/1449374042)
|
||||
, [Barnes & Nobles](http://www.barnesandnoble.com/w/mastering-bitcoin-andreas-m-antonopoulos/1119253039?ean=9781449374044
|
||||
) and [O'Reilly Media](http://shop.oreilly.com/product/0636920032281.do). For a limited time, the book is also sold for bitcoin at the [author's site](http://bitcoinbook.info)
|
||||
|
||||
# Purchasing
|
||||
# Source
|
||||
|
||||
"Mastering Bitcoin" will be available in print and e-book format in Fall 2014. To pre-order your copy, please visit:
|
||||
The book's source code, found in this repository, is a near-final draft before the publisher's editorial process. Please do not submit changes here, instead use the [errata](http://www.oreilly.com/catalog/errata.csp?isbn=0636920032281) page on the publisher's site.
|
||||
|
||||
http://bitcoinbook.info
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-nd/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">Mastering Bitcoin: Unlocking digital crypto-currencies</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="http://antonopoulos.com/" property="cc:attributionName" rel="cc:attributionURL">Andreas M. Antonopoulos LLC</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/">Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License</a>.
|
186
appdx-bx.asciidoc
Normal file
186
appdx-bx.asciidoc
Normal file
@ -0,0 +1,186 @@
|
||||
[[appdx_bx]]
|
||||
[appendix]
|
||||
|
||||
== Available Bitcoin Explorer Commands
|
||||
|
||||
((("Bitcoin Explorer commands","commands in", id="ix_appdx-bx-asciidoc0", range="startofrange")))
|
||||
|
||||
----
|
||||
Usage: bx COMMAND [--help]
|
||||
|
||||
Info: The bx commands are:
|
||||
|
||||
address-decode
|
||||
address-embed
|
||||
address-encode
|
||||
address-validate
|
||||
base16-decode
|
||||
base16-encode
|
||||
base58-decode
|
||||
base58-encode
|
||||
base58check-decode
|
||||
base58check-encode
|
||||
base64-decode
|
||||
base64-encode
|
||||
bitcoin160
|
||||
bitcoin256
|
||||
btc-to-satoshi
|
||||
ec-add
|
||||
ec-add-secrets
|
||||
ec-multiply
|
||||
ec-multiply-secrets
|
||||
ec-new
|
||||
ec-to-address
|
||||
ec-to-public
|
||||
ec-to-wif
|
||||
fetch-balance
|
||||
fetch-header
|
||||
fetch-height
|
||||
fetch-history
|
||||
fetch-stealth
|
||||
fetch-tx
|
||||
fetch-tx-index
|
||||
hd-new
|
||||
hd-private
|
||||
hd-public
|
||||
hd-to-address
|
||||
hd-to-ec
|
||||
hd-to-public
|
||||
hd-to-wif
|
||||
help
|
||||
input-set
|
||||
input-sign
|
||||
input-validate
|
||||
message-sign
|
||||
message-validate
|
||||
mnemonic-decode
|
||||
mnemonic-encode
|
||||
ripemd160
|
||||
satoshi-to-btc
|
||||
script-decode
|
||||
script-encode
|
||||
script-to-address
|
||||
seed
|
||||
send-tx
|
||||
send-tx-node
|
||||
send-tx-p2p
|
||||
settings
|
||||
sha160
|
||||
sha256
|
||||
sha512
|
||||
stealth-decode
|
||||
stealth-encode
|
||||
stealth-public
|
||||
stealth-secret
|
||||
stealth-shared
|
||||
tx-decode
|
||||
tx-encode
|
||||
uri-decode
|
||||
uri-encode
|
||||
validate-tx
|
||||
watch-address
|
||||
wif-to-ec
|
||||
wif-to-public
|
||||
wrap-decode
|
||||
wrap-encode
|
||||
|
||||
Bitcoin Explorer home page:
|
||||
|
||||
https://github.com/libbitcoin/libbitcoin-explorer
|
||||
|
||||
Bitcoin Explorer user documentation:
|
||||
|
||||
https://github.com/libbitcoin/libbitcoin-explorer/wiki
|
||||
|
||||
----
|
||||
|
||||
Next, we look at some examples of using Bitcoin Explorer commands to experiment with keys and addresses.
|
||||
|
||||
Generate a random "seed" value using the((("Bitcoin Explorer","seed command")))((("seed command (bx)"))) +seed+ command, which uses the operating system's random number generator. Pass the seed to the((("Bitcoin Explorer","ec-new command")))((("ec-new command (bx)"))) +ec-new+ command to generate a new private key. We save the standard output into the file _private_key_:
|
||||
|
||||
----
|
||||
$ bx seed | bx ec-new > private_key
|
||||
$ cat private_key
|
||||
73096ed11ab9f1db6135857958ece7d73ea7c30862145bcc4bbc7649075de474
|
||||
----
|
||||
|
||||
Now, generate the public key from that private key using the((("Bitcoin Explorer","ec-to-public command")))((("ec-to-public command (bx)"))) +ec-to-public+ command. We pass the _private_key_ file into the standard input and save the standard output of the command into a new file _public_key_:
|
||||
|
||||
----
|
||||
$ bx ec-to-public < private_key > public_key
|
||||
$ cat public_key
|
||||
02fca46a6006a62dfdd2dbb2149359d0d97a04f430f12a7626dd409256c12be500
|
||||
----
|
||||
|
||||
We can reformat the +public_key+ as an address using the((("Bitcoin Explorer","ec-to-address command")))((("ec-to-address command (bx)"))) +ec-to-address+ command. We pass the _public_key_ into standard input:
|
||||
|
||||
----
|
||||
$ bx ec-to-address < public_key
|
||||
17re1S4Q8ZHyCP8Kw7xQad1Lr6XUzWUnkG
|
||||
----
|
||||
|
||||
Keys generated in this manner produce a type-0 nondeterministic wallet. That means that each key is generated from an independent seed. Bitcoin Explorer commands can also generate keys deterministically, in accordance with BIP0032. In this case a "master" key is created from a seed and then extended deterministically to produce a tree of subkeys, resulting in a type-2 deterministic wallet.
|
||||
|
||||
First, we we use the((("Bitcoin Explorer","seed command")))((("seed command (bx)"))) +seed+ and((("Bitcoin Explorer","hd-new command")))((("hd-new command (bx)"))) +hd-new+ commands to generate a master key that will be used as the basis to derive a hierarchy of keys.
|
||||
|
||||
----
|
||||
$ bx seed > seed
|
||||
$ cat seed
|
||||
eb68ee9f3df6bd4441a9feadec179ff1
|
||||
|
||||
$ bx hd-new < seed > master
|
||||
$ cat master
|
||||
xprv9s21ZrQH143K2BEhMYpNQoUvAgiEjArAVaZaCTgsaGe6LsAnwubeiTcDzd23mAoyizm9cApe51gNfLMkBqkYoWWMCRwzfuJk8RwF1SVEpAQ
|
||||
----
|
||||
|
||||
We now use the((("Bitcoin Explorer","hd-private command")))((("hd-private command (bx)"))) +hd-private+ command to generate a hardened "account" key and a sequence of two private keys within the account.
|
||||
|
||||
----
|
||||
$ bx hd-private --hard < master > account
|
||||
$ cat account
|
||||
xprv9vkDLt81dTKjwHB8fsVB5QK8cGnzveChzSrtCfvu3aMWvQaThp59ueufuyQ8Qi3qpjk4aKsbmbfxwcgS8PYbgoR2NWHeLyvg4DhoEE68A1n
|
||||
|
||||
$ bx hd-private --index 0 < account
|
||||
xprv9xHfb6w1vX9xgZyPNXVgAhPxSsEkeRcPHEUV5iJcVEsuUEACvR3NRY3fpGhcnBiDbvG4LgndirDsia1e9F3DWPkX7Tp1V1u97HKG1FJwUpU
|
||||
|
||||
$ bx hd-private --index 1 < account
|
||||
xprv9xHfb6w1vX9xjc8XbN4GN86jzNAZ6xHEqYxzbLB4fzHFd6VqCLPGRZFsdjsuMVERadbgDbziCRJru9n6tzEWrASVpEdrZrFidt1RDfn4yA3
|
||||
----
|
||||
|
||||
Next we use the((("Bitcoin Explorer","hd-public command")))((("hd-public command (bx)"))) +hd-public+ command to generate the corresponding sequence of two public keys.
|
||||
|
||||
----
|
||||
$ bx hd-public --index 0 < account
|
||||
xpub6BH1zcTuktiFu43rUZ2gXqLgzu5F3tLEeTQ5t6iE3aQtM2VMTxMcyLN9fYHiGhGpQe9QQYmqL2eYPFJ3vezHz5wzaSW4FiGrseNDR4LKqTy
|
||||
|
||||
$ bx hd-public --index 1 < account
|
||||
xpub6BH1zcTuktiFx6CzhPbGjG3UYQ13WR16CmtbPiagEKpEVtpyjshWyMaMV1cn7nUPUkgQHPVXJVqsrA8xWbGQDhohEcDFTEYMvYzwRD7Juf8
|
||||
----
|
||||
|
||||
The public keys can also be derived from their corresponding private keys using the((("Bitcoin Explorer","hd-to-public command")))((("hd-to-public command (bx)"))) +hd-to-public+ command.
|
||||
|
||||
----
|
||||
$ bx hd-private --index 0 < account | bx hd-to-public
|
||||
xpub6BH1zcTuktiFu43rUZ2gXqLgzu5F3tLEeTQ5t6iE3aQtM2VMTxMcyLN9fYHiGhGpQe9QQYmqL2eYPFJ3vezHz5wzaSW4FiGrseNDR4LKqTy
|
||||
|
||||
$ bx hd-private --index 1 < account | bx hd-to-public
|
||||
xpub6BH1zcTuktiFx6CzhPbGjG3UYQ13WR16CmtbPiagEKpEVtpyjshWyMaMV1cn7nUPUkgQHPVXJVqsrA8xWbGQDhohEcDFTEYMvYzwRD7Juf8
|
||||
----
|
||||
|
||||
We can generate a practically limitless number of keys in a deterministic chain, all derived from a single seed. This technique is used in many wallet applications to generate keys that can be backed up and restored with a single seed value. This is easier than having to back up the wallet with all its randomly generated keys every time a new key is created.
|
||||
|
||||
The seed can be encoded using the((("Bitcoin Explorer","mnemonic-encode command")))((("mnemonic-encode command (bx)"))) +mnemonic-encode+ command.
|
||||
|
||||
----
|
||||
$ bx hd-mnemonic < seed > words
|
||||
adore repeat vision worst especially veil inch woman cast recall dwell appreciate
|
||||
----
|
||||
|
||||
The seed can then be decoded using the((("Bitcoin Explorer","mnemonic-decode command")))((("mnemonic-decode command (bx)"))) +mnemonic-decode+ command.
|
||||
|
||||
----
|
||||
$ bx mnemonic-decode < words
|
||||
eb68ee9f3df6bd4441a9feadec179ff1
|
||||
----
|
||||
|
||||
Mnemonic encoding can make the seed easier to record and even remember.(((range="endofrange", startref="ix_appdx-bx-asciidoc0")))
|
@ -1,211 +0,0 @@
|
||||
[[appdx_sx]]
|
||||
[appendix]
|
||||
|
||||
== Available Commands with sx Tools
|
||||
|
||||
((("sx tools","commands in", id="ix_appdx-sx-asciidoc0", range="startofrange")))
|
||||
|
||||
----
|
||||
The sx commands are:
|
||||
|
||||
DEPRECATED
|
||||
ELECTRUM STYLE DETERMINISTIC KEYS AND ADDRESSES
|
||||
genaddr Generate a Bitcoin address deterministically from a wallet
|
||||
seed or master public key.
|
||||
genpriv Generate a private key deterministically from a seed.
|
||||
genpub Generate a public key deterministically from a wallet
|
||||
seed or master public key.
|
||||
mpk Extract a master public key from a deterministic wallet seed.
|
||||
newseed Create a new deterministic wallet seed.
|
||||
|
||||
EXPERIMENTAL
|
||||
APPS
|
||||
wallet Experimental command-line wallet.
|
||||
|
||||
OFFLINE BLOCKCHAIN
|
||||
HEADERS
|
||||
showblkhead Show the details of a block header.
|
||||
|
||||
OFFLINE KEYS AND ADDRESSES
|
||||
BASIC
|
||||
addr See Bitcoin address of a public or private key.
|
||||
embed-addr Generate an address used for embedding record of data into the
|
||||
blockchain
|
||||
get-pubkey Get the pubkey of an address if available.
|
||||
newkey Create a new private key.
|
||||
pubkey See the public part of a private key.
|
||||
validaddr Validate an address.
|
||||
BRAIN STORAGE
|
||||
brainwallet Make 256 bit bitcoin private key from an arbitrary passphrase.
|
||||
mnemonic Make 12 word mnemonic out of 128 bit electrum or bip32 seed.
|
||||
HD / BIP32
|
||||
hd-priv Create a private HD key from another HD private key.
|
||||
hd-pub Create an HD public key from another HD private or public key.
|
||||
hd-seed Create a random new HD key.
|
||||
hd-to-address Convert an HD public or private key to a Bitcoin address.
|
||||
hd-to-wif Convert an HD private key to a WIF private key.
|
||||
MULTISIG ADDRESSES
|
||||
scripthash Create BIP 16 script hash address from raw script hex.
|
||||
STEALTH
|
||||
stealth-addr See a stealth address from given input.
|
||||
stealth-initiate Initiate a new stealth payment.
|
||||
stealth-newkey Generate new stealth keys and an address.
|
||||
stealth-show-addr Show details for a stealth address.
|
||||
stealth-uncover Uncover a stealth address.
|
||||
stealth-uncover-secret Uncover a stealth secret.
|
||||
|
||||
OFFLINE TRANSACTIONS
|
||||
SCRIPTING
|
||||
mktx Create an unsigned tx.
|
||||
rawscript Create the raw hex representation from a script.
|
||||
set-input Set a transaction input.
|
||||
showscript Show the details of a raw script.
|
||||
showtx Show the details of a transaction.
|
||||
sign-input Sign a transaction input.
|
||||
unwrap Validates checksum and recovers version byte and original data
|
||||
from hexstring.
|
||||
validsig Validate a transaction input's signature.
|
||||
wrap Adds version byte and checksum to hexstring.
|
||||
|
||||
ONLINE (BITCOIN P2P)
|
||||
BLOCKCHAIN UPDATES
|
||||
sendtx-node Send transaction to a single node.
|
||||
sendtx-p2p Send tx to bitcoin network.
|
||||
|
||||
ONLINE (BLOCKCHAIN.INFO)
|
||||
BLOCKCHAIN QUERIES (blockchain.info)
|
||||
bci-fetch-last-height Fetch the last block height using blockchain.info.
|
||||
bci-history Get list of output points, values, and their spends
|
||||
from blockchain.info
|
||||
BLOCKCHAIN UPDATES
|
||||
sendtx-bci Send tx to blockchain.info/pushtx.
|
||||
|
||||
ONLINE (BLOCKEXPLORER.COM)
|
||||
BLOCKCHAIN QUERIES (blockexplorer.com)
|
||||
blke-fetch-transaction Fetches a transaction from blockexplorer.com
|
||||
|
||||
ONLINE (OBELISK)
|
||||
BLOCKCHAIN QUERIES
|
||||
balance Show balance of a Bitcoin address in satoshis.
|
||||
fetch-block-header Fetch raw block header.
|
||||
fetch-last-height Fetch the last block height.
|
||||
fetch-stealth Fetch a stealth information using a network connection
|
||||
to make requests against the obelisk load balancer backend.
|
||||
fetch-transaction Fetch a raw transaction using a network connection to
|
||||
make requests against the obelisk load balancer
|
||||
backend.
|
||||
fetch-transaction-index
|
||||
Fetch block height and index in block of transaction.
|
||||
get-utxo Get enough unspent transaction outputs from a given set
|
||||
of addresses to pay a given number of satoshis.
|
||||
history Get list of output points, values, and their spends for
|
||||
an address. grep can filter for just unspent outputs which can
|
||||
be fed into mktx.
|
||||
validtx Validate a transaction.
|
||||
BLOCKCHAIN UPDATES
|
||||
sendtx-obelisk Send tx to obelisk server.
|
||||
BLOCKCHAIN WATCHING
|
||||
monitor Monitor an address.
|
||||
watchtx Watch transactions from the network searching for a certain
|
||||
hash.
|
||||
OBELISK ADMIN
|
||||
initchain Initialize a new blockchain.
|
||||
|
||||
UTILITY
|
||||
EC MATH
|
||||
ec-add-modp Calculate the result of INTEGER + INTEGER.
|
||||
ec-multiply Multiply an integer and a point together.
|
||||
ec-tweak-add Calculate the result of POINT + INTEGER * G.
|
||||
FORMAT (BASE 58)
|
||||
base58-decode Convert from base58 to hex.
|
||||
base58-encode Convert from hex to base58.
|
||||
FORMAT (BASE58CHECK)
|
||||
base58check-decode Convert from base58check to hex.
|
||||
base58check-encode Convert from hex to base58check.
|
||||
decode-addr Decode a address from base58check form to internal RIPEMD
|
||||
representation.
|
||||
encode-addr Encode an address from internal RIPEMD representation to
|
||||
base58check form.
|
||||
FORMAT (WIF)
|
||||
secret-to-wif Convert a secret exponent value to Wallet Import Format.
|
||||
wif-to-secret Convert a Wallet Import Format to secret exponent value.
|
||||
HASHES
|
||||
ripemd-hash RIPEMD hash data from STDIN.
|
||||
sha256 Perform SHA256 hash of data.
|
||||
MISC
|
||||
qrcode Generate Bitcoin QR codes offline.
|
||||
SATOSHI MATH
|
||||
btc Convert Satoshis into Bitcoins.
|
||||
satoshi Convert Bitcoins into Satoshis.
|
||||
|
||||
See 'sx help COMMAND' for more information on a specific command.
|
||||
|
||||
----
|
||||
|
||||
Next, we look at some examples of using sx tools to experiment with keys and addresses.
|
||||
|
||||
Generate a new private key with the operating system's random number generator by using the +newkey+ command. We save the standard output into the file _private_key_:
|
||||
|
||||
----
|
||||
$ sx newkey > private_key
|
||||
$ cat private_key
|
||||
5Jgx3UAaXw8AcCQCi1j7uaTaqpz2fqNR9K3r4apxdYn6rTzR1PL
|
||||
----
|
||||
|
||||
Now, generate the public key from that private key using the +pubkey+ command. Pass the _private_key_ file into the standard input and save the standard output of the command into a new file _public_key_:
|
||||
|
||||
----
|
||||
$ sx pubkey < private_key > public_key
|
||||
$ cat public_key
|
||||
02fca46a6006a62dfdd2dbb2149359d0d97a04f430f12a7626dd409256c12be500
|
||||
----
|
||||
|
||||
We can reformat the +public_key+ as an address using the +addr+ command. We pass the +public_key+ into standard input:
|
||||
|
||||
----
|
||||
$ sx addr < public_key
|
||||
17re1S4Q8ZHyCP8Kw7xQad1Lr6XUzWUnkG
|
||||
----
|
||||
|
||||
The keys generated are so called type-0 nondeterministic keys. That means that each one is generated from a random number generator. The sx tools also support type-2 deterministic keys, where a "master" key is created and then extended to produce a chain or tree of subkeys.
|
||||
|
||||
First, we generate a "seed" that will be used as the basis to derive a chain of keys, compatible with the Electrum wallet and other similar implementations. We use the +newseed+ command to produce a seed value:
|
||||
|
||||
----
|
||||
$ sx newseed > seed
|
||||
$ cat seed
|
||||
eb68ee9f3df6bd4441a9feadec179ff1
|
||||
----
|
||||
|
||||
The seed value can also be exported as a word mnemonic that is human readable and easier to store and type than a hexadecimal string
|
||||
using the +mnemonic+ command:
|
||||
|
||||
----
|
||||
$ sx mnemonic < seed > words
|
||||
$ cat words
|
||||
adore repeat vision worst especially veil inch woman cast recall dwell appreciate
|
||||
----
|
||||
|
||||
The mnemonic words can be used to reproduce the seed using the +mnemonic+ command again:
|
||||
|
||||
----
|
||||
$ sx mnemonic < words
|
||||
eb68ee9f3df6bd4441a9feadec179ff1
|
||||
----
|
||||
|
||||
With the seed, we can now generate a sequence of private and public keys, a key chain. We use the +genpriv+ command to generate a sequence of private keys from a seed and the +addr+ command to generate the corresponding public key:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
$ sx genpriv 0 < seed
|
||||
5JzY2cPZGViPGgXZ4Syb9Y4eUGjJpVt6sR8noxrpEcqgyj7LK7i
|
||||
$ sx genpriv 0 < seed | sx addr
|
||||
1esVQV2vR9JZPhFeRaeWkAhzmWq7Fi7t7
|
||||
|
||||
$ sx genpriv 1 < seed
|
||||
5JdtL7ckAn3iFBFyVG1Bs3A5TqziFTaB9f8NeyNo8crnE2Sw5Mz
|
||||
$ sx genpriv 1 < seed | sx addr
|
||||
1G1oTeXitk76c2fvQWny4pryTdH1RTqSPW
|
||||
----
|
||||
|
||||
With deterministic keys we can generate and regenerate thousands of keys, all derived from a single seed in a deterministic chain. This technique is used in many wallet applications to generate keys that can be backed up and restored with a simple multiword mnemonic. This is easier than having to back up the wallet with all its randomly generated keys every time a new key is created.(((range="endofrange", startref="ix_appdx-sx-asciidoc0")))
|
@ -34,7 +34,7 @@ include::appdx-bips.asciidoc[]
|
||||
|
||||
include::appdx-pycoin.asciidoc[]
|
||||
|
||||
include::appdx-sx.asciidoc[]
|
||||
include::appdx-bx.asciidoc[]
|
||||
|
||||
include::index.asciidoc[]
|
||||
|
||||
|
@ -1131,7 +1131,9 @@ As before, we can also examine this in more detail using the +getrawtransaction+
|
||||
|
||||
Alternative implementations include:
|
||||
|
||||
https://libbitcoin.dyne.org/[libbitcoin and sx tools]:: A C++ multithreaded full-node client and library with command-line tools
|
||||
https://github.com/libbitcoin/libbitcoin[libbitcoin]:: ((("libbitcoin library")))Bitcoin Cross-Platform C++ Development Toolkit
|
||||
https://github.com/libbitcoin/libbitcoin-explorer[bitcoin explorer]:: ((("Bitcoin Explorer")))Bitcoin Command Line Tool
|
||||
https://github.com/libbitcoin/libbitcoin-server[bitcoin server]:: ((("Bitcoin Server")))Bitcoin Full Node and Query Server
|
||||
https://code.google.com/p/bitcoinj/[bitcoinj]:: ((("BitcoinJ library")))A Java full-node client library
|
||||
https://opensource.conformal.com/wiki/btcd[btcd]:: ((("btcd","client")))A Go language full-node bitcoin client
|
||||
https://bitsofproof.com[Bits of Proof (BOP)]:: ((("Bits of Proof (BOP)")))A Java enterprise-class implementation of bitcoin
|
||||
@ -1141,26 +1143,39 @@ https://github.com/richardkiss/pycoin[pycoin]:: ((("pycoin library")))Another Py
|
||||
|
||||
Many more libraries exist in a variety of other programming languages and more are created all the time.
|
||||
|
||||
[[sx_tools]]
|
||||
==== Libbitcoin and sx Tools
|
||||
[[libbitcoin]]
|
||||
==== Libbitcoin and Bitcoin Explorer
|
||||
|
||||
((("libbitcoin library")))((("libraries, alternative","libbitcoin library")))((("sx tools")))The libbitcoin library is a C++ scalable multithreaded and modular implementation that supports a full-node client and a command-line toolset called sx, which offers many of the same capabilities as the bitcoind client commands we illustrated in this chapter. The sx tools also offer some key management and manipulation tools that are not offered by bitcoind, including type-2 deterministic keys and key mnemonics.
|
||||
The ((("libbitcoin library")))((("libraries, alternative","libbitcoin library")))libbitcoin library is a cross-platform C++ development toolkit that supports the ((("Bitcoin Server")))((("libraries, alternative","Bitcoin Server")))libbitcoin-server full node and the ((("Bitcoin Explorer")))((("libraries, alternative","Bitcoin Explorer")))Bitcoin Explorer (bx) command line tool.
|
||||
|
||||
===== Installing sx
|
||||
The bx commands offer many of the same capabilities as the bitcoind client commands we illustrated in this chapter. The bx commands also offer some key management and manipulation tools that are not offered by bitcoind, including type-2 deterministic keys and mnemonic key encoding, as well as stealth address, payment and query support.
|
||||
|
||||
((("sx tools","installing")))To install sx and the supporting library libbitcoin, download and run the online installer on a Linux system:
|
||||
===== Installing Bitcoin Explorer
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
$ wget http://sx.dyne.org/install-sx.sh
|
||||
$ sudo bash ./install-sx.sh
|
||||
----
|
||||
((("Bitcoin Explorer","installing")))To use Bitcoin Explorer simply download the signed executable for your operating system. Builds are available for mainnet and testnet for Linux, OSX and Windows.
|
||||
|
||||
You should now have the sx tools installed. Type +sx+ with no parameters to display the help text, which lists all the available commands (see <<appdx_sx>>).
|
||||
https://github.com/libbitcoin/libbitcoin-explorer/wiki/Download
|
||||
|
||||
Type +bx+ with no parameters to display the list of all available commands (see <<appdx_bx>>).
|
||||
|
||||
Bitcoin Explorer also provides an installer for building from sources on Linux and OSX as well as Visual Studio projects for Windows. Sources can also be built manually using Autotools. These also install the ((("libbitcoin library","installing")))libbitcoin library dependency.
|
||||
|
||||
https://github.com/libbitcoin/libbitcoin-explorer/wiki/Build
|
||||
|
||||
[TIP]
|
||||
====
|
||||
The sx toolkit offers many useful commands for encoding and decoding addresses, and converting to and from different formats and representations. Use them to explore the various formats such as Base58, Base58Check, hex, etc.
|
||||
Bitcoin Explorer offers many useful commands for encoding and decoding addresses, and converting to and from different formats and representations. Use them to explore the various formats such as Base16 (hex), Base58, Base58Check, Base64, etc.
|
||||
====
|
||||
|
||||
===== Installing Libbitcoin
|
||||
|
||||
((("libbitcoin library","installing")))The libbitcoin library provides an installer for building from sources on Linux and OSX as well as Visual Studio projects for Windows. Sources can also be built manually using Autotools.
|
||||
|
||||
https://github.com/libbitcoin/libbitcoin/wiki/Build
|
||||
|
||||
[TIP]
|
||||
====
|
||||
The Bitcoin Explorer installer installs both bx and the libbitcoin library, so if you have built bx from sources you can skip this step.
|
||||
====
|
||||
|
||||
==== pycoin
|
||||
|
@ -87,10 +87,10 @@ The +dumpprivkey+ command opens the wallet and extracts the private key that was
|
||||
The +dumpprivkey+ command is not generating a private key from a public key, as this is impossible. The command simply reveals the private key that is already known to the wallet and which was generated by the getnewaddress command.
|
||||
=====================================================================
|
||||
|
||||
You can also use the command-line sx tools (see <<sx_tools>>) to generate and display private keys with the sx command +newkey+: (((range="endofrange", startref="ix_ch04-asciidoc3")))(((range="endofrange", startref="ix_ch04-asciidoc2")))(((range="endofrange", startref="ix_ch04-asciidoc1")))
|
||||
You can also use the Bitcoin Explorer command-line tool (see <<libbitcoin>>) to generate and display private keys with the commands((("Bitcoin Explorer","seed command")))((("seed command (bx)"))) +seed+,((("Bitcoin Explorer","ec-new command")))((("ec-new command (bx)"))) +ec-new+ and((("Bitcoin Explorer","ec-to-wif command")))((("ec-to-wif command (bx)"))) +ec-to-wif+: (((range="endofrange", startref="ix_ch04-asciidoc3")))(((range="endofrange", startref="ix_ch04-asciidoc2")))(((range="endofrange", startref="ix_ch04-asciidoc1")))
|
||||
|
||||
----
|
||||
$ sx newkey
|
||||
$ bx seed | bx ec-new | bx ec-to-wif
|
||||
5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
|
||||
----
|
||||
|
||||
@ -340,7 +340,7 @@ Address: 1PRTTaJesdNovgne6Ehcdu1fpEdX7913CK
|
||||
[[priv_formats]]
|
||||
===== Private key formats
|
||||
|
||||
((("private keys","format")))((("sx tools","modifying private key formats with")))The private key can be represented in a number of different formats, all of which correspond to the same 256-bit number. <<table_4-2>> shows three common formats used to represent private keys.
|
||||
((("private keys","format")))((("Bitcoin Explorer","modifying private key formats with")))The private key can be represented in a number of different formats, all of which correspond to the same 256-bit number. <<table_4-2>> shows three common formats used to represent private keys.
|
||||
|
||||
[[table_4-2]]
|
||||
.Private key representations (encoding formats)
|
||||
@ -359,38 +359,63 @@ Address: 1PRTTaJesdNovgne6Ehcdu1fpEdX7913CK
|
||||
[options="header"]
|
||||
|=======
|
||||
|Format | Private Key
|
||||
| Hex | 1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD
|
||||
| Hex | 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd
|
||||
| WIF | 5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
|
||||
| WIF-compressed | KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ
|
||||
|=======
|
||||
|
||||
All of these representations are different ways of showing the same number, the same private key. They look different, but any one format can easily be converted to any other format.
|
||||
|
||||
===== Decode from Base58Check to hex
|
||||
|
||||
((("Base58Check encoding","decoding to hex")))((("sx tools","decoding Base58Check to/from hex")))The sx tools package (See <<sx_tools>>) makes it easy to write shell scripts and command-line "pipes" that manipulate bitcoin keys, addresses, and transactions. You can use sx tools to decode the Base58Check format on the command line.
|
||||
|
||||
We use the((("base58check-decode command (sx tools)"))) +base58check-decode+ command:
|
||||
We use the((("Bitcoin Explorer","wif-to-ec command")))((("wif-to-ec command (bx)"))) +wif-to-ec+ command from Bitcoin Explorer (see <<libbitcoin>>) to show that both WIF keys represent the same private key:
|
||||
----
|
||||
$ sx base58check-decode 5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
|
||||
1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd 128
|
||||
$ bx wif-to-ec 5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
|
||||
1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd
|
||||
|
||||
$ bx wif-to-ec KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ
|
||||
1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd
|
||||
----
|
||||
|
||||
The result is the hexadecimal key, followed by the Wallet Import Format (WIF) version prefix 128.
|
||||
===== Decode from Base58Check
|
||||
|
||||
((("Base58Check encoding","decoding to hex")))The Bitcoin Explorer commands (see <<libbitcoin>>) make it easy to write shell scripts and command-line "pipes" that manipulate bitcoin keys, addresses, and transactions. You can use Bitcoin Explorer to decode the Base58Check format on the command line.
|
||||
|
||||
We use the((("Bitcoin Explorer","base58check-decode command")))((("base58check-decode command (bx)"))) +base58check-decode+ command to decode the uncompressed key:
|
||||
----
|
||||
$ bx base58check-decode 5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
|
||||
wrapper
|
||||
{
|
||||
checksum 4286807748
|
||||
payload 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd
|
||||
version 128
|
||||
}
|
||||
----
|
||||
|
||||
The result contains the key as payload, the Wallet Import Format (WIF) version prefix 128, and a checksum.
|
||||
|
||||
Notice that the "payload" of the compressed key is appended with the suffix +01+, signalling that the derived public key is to be compressed.
|
||||
----
|
||||
$ bx base58check-decode KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ
|
||||
wrapper
|
||||
{
|
||||
checksum 2339607926
|
||||
payload 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd01
|
||||
version 128
|
||||
}
|
||||
----
|
||||
|
||||
===== Encode from hex to Base58Check
|
||||
|
||||
((("Base58Check encoding","from hex")))To encode into Base58Check (the opposite of the previous command), we provide the hex private key, followed by the((("Base58Check encoding","WIF prefix for")))((("Wallet Import Format (WIF)"))) Wallet Import Format (WIF) version prefix 128:
|
||||
((("Base58Check encoding","from hex")))To encode into Base58Check (the opposite of the previous command), we use the((("Bitcoin Explorer","base58check-encode command")))((("base58check-encode command (bx)"))) +base58check-encode+ command from Bitcoin Explorer (see <<libbitcoin>>) and provide the hex private key, followed by the((("Base58Check encoding","WIF prefix for")))((("Wallet Import Format (WIF)"))) Wallet Import Format (WIF) version prefix 128:
|
||||
----
|
||||
$ sx base58check-encode 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd 128
|
||||
bx base58check-encode 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd --version 128
|
||||
5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
|
||||
----
|
||||
|
||||
===== Encode from hex (compressed key) to Base58Check encoding
|
||||
===== Encode from hex (compressed key) to Base58Check
|
||||
|
||||
((("compressed keys","encoding/decoding from Base58Check")))To encode into Base58Check as a "compressed" private key (see <<comp_priv>>), we add the suffix +01+ to the end of the hex key and then encode as above:
|
||||
((("compressed keys","encoding/decoding from Base58Check")))To encode into Base58Check as a "compressed" private key (see <<comp_priv>>), we append the suffix +01+ to the hex key and then encode as above:
|
||||
----
|
||||
$ sx base58check-encode 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd01 128
|
||||
$ bx base58check-encode 1e99423a4ed27608a15a2616a2b0e9e52ced330ac530edcc32c8ffc6a526aedd01 --version 128
|
||||
KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ
|
||||
----
|
||||
|
||||
@ -626,7 +651,7 @@ fce540af281bf7cdeade0dd2c1c795bd02f1e4049e205a0158906c343
|
||||
((("deterministic wallets","hierarchical", id="ix_ch04-asciidoc24", range="startofrange")))((("hierarchical deterministic wallets (HD wallets)", id="ix_ch04-asciidoc25", range="startofrange")))((("BIP0032", id="ix_ch04-asciidoc25a", range="startofrange")))((("BIP0044", id="ix_ch04-asciidoc25b", range="startofrange")))Deterministic wallets were developed to make it easy to derive many keys from a single "seed." The most advanced form of deterministic wallets is the _hierarchical deterministic wallet_ or _HD wallet_ defined by the BIP0032 standard. Hierarchical deterministic wallets contain keys derived in a tree structure, such that a parent key can derive a sequence of children keys, each of which can derive a sequence of grandchildren keys, and so on, to an infinite depth. This tree structure is illustrated in <<Type2_wallet>>.((("hierarchical deterministic wallets (HD wallets)","tree structure for")))
|
||||
|
||||
[[Type2_wallet]]
|
||||
.Type-2 hierarchical deterministic wallet: a tree of keys generated from a seed
|
||||
.Type-2 hierarchical deterministic wallet: a tree of keys generated from a single seed
|
||||
image::images/msbt_0409.png["HD wallet"]
|
||||
|
||||
[TIP]
|
||||
@ -796,25 +821,25 @@ BIP0044 specifies the structure as consisting of five predefined tree levels:
|
||||
| m/44'/2'/0'/0/1 | The second private key in the Litecoin main account, for signing transactions
|
||||
|=======
|
||||
|
||||
===== Experimenting with HD wallets using sx tools
|
||||
===== Experimenting with HD wallets using Bitcoin Explorer
|
||||
|
||||
((("hierarchical deterministic wallets (HD wallets)","sx tools and")))((("sx tools","HD wallets and")))Using the command-line tool +sx+, introduced in <<ch03_bitcoin_client>>, you can experiment with generating and extending BIP0032 deterministic keys, as well as displaying them in different formats: (((range="endofrange", startref="ix_ch04-asciidoc25b")))(((range="endofrange", startref="ix_ch04-asciidoc25a")))(((range="endofrange", startref="ix_ch04-asciidoc25")))(((range="endofrange", startref="ix_ch04-asciidoc24")))(((range="endofrange", startref="ix_ch04-asciidoc23")))
|
||||
((("hierarchical deterministic wallets (HD wallets)","Bitcoin Explorer and")))((("Bitcoin Explorer","HD wallets and")))Using the Bitcoin Explorer command-line tool introduced in <<ch03_bitcoin_client>>, you can experiment with generating and extending BIP0032 deterministic keys, as well as displaying them in different formats((("Bitcoin Explorer","seed command")))((("seed command (bx)")))((("Bitcoin Explorer","hd-seed command")))((("hd-seed command (bx)")))((("Bitcoin Explorer","hd-public command")))((("hd-public command (bx)")))((("Bitcoin Explorer","hd-private command")))((("hd-private command (bx)")))((("Bitcoin Explorer","hd-to-address command")))((("hd-to-address command (bx)")))((("Bitcoin Explorer","hd-to-wif command")))((("hd-to-wif command (bx)"))): (((range="endofrange", startref="ix_ch04-asciidoc25b")))(((range="endofrange", startref="ix_ch04-asciidoc25a")))(((range="endofrange", startref="ix_ch04-asciidoc25")))(((range="endofrange", startref="ix_ch04-asciidoc24")))(((range="endofrange", startref="ix_ch04-asciidoc23")))
|
||||
|
||||
====
|
||||
[source, bash]
|
||||
----
|
||||
$ sx hd-seed > m # create a new master private key from a seed and store in file "m"
|
||||
$ bx seed | bx hd-seed > m # create a new master private key from a seed and store in file "m"
|
||||
$ cat m # show the master extended private key
|
||||
xprv9s21ZrQH143K38iQ9Y5p6qoB8C75TE71NfpyQPdfGvzghDt39DHPFpovvtWZaRgY5uPwV7RpEgHs7cvdgfiSjLjjbuGKGcjRyU7RGGSS8Xa
|
||||
$ cat m | sx hd-pub 0 # generate the M/0 extended public key
|
||||
$ cat m | bx hd-public # generate the M/0 extended public key
|
||||
xpub67xpozcx8pe95XVuZLHXZeG6XWXHpGq6Qv5cmNfi7cS5mtjJ2tgypeQbBs2UAR6KECeeMVKZBPLrtJunSDMstweyLXhRgPxdp14sk9tJPW9
|
||||
$ cat m | sx hd-priv 0 # generate the m/0 extended private key
|
||||
$ cat m | bx hd-private # generate the m/0 extended private key
|
||||
xprv9tyUQV64JT5qs3RSTJkXCWKMyUgoQp7F3hA1xzG6ZGu6u6Q9VMNjGr67Lctvy5P8oyaYAL9CAWrUE9i6GoNMKUga5biW6Hx4tws2six3b9c
|
||||
$ cat m | sx hd-priv 0 | sx hd-to-wif # show the private key of m/0 as a WIF
|
||||
$ cat m | bx hd-private | bx hd-to-wif # show the private key of m/0 as a WIF
|
||||
L1pbvV86crAGoDzqmgY85xURkz3c435Z9nirMt52UbnGjYMzKBUN
|
||||
$ cat m | sx hd-pub 0 | sx hd-to-address # show the bitcoin address of M/0
|
||||
$ cat m | bx hd-public | bx hd-to-address # show the bitcoin address of M/0
|
||||
1CHCnCjgMNb6digimckNQ6TBVcTWBAmPHK
|
||||
$ cat m | sx hd-priv 0 | sx hd-priv 12 --hard | sx hd-priv 4 # generate m/0/12'/4
|
||||
$ cat m | bx hd-private | bx hd-private --index 12 --hard | bx hd-private --index 4 # generate m/0/12'/4
|
||||
xprv9yL8ndfdPVeDWJenF18oiHguRUj8jHmVrqqD97YQHeTcR3LCeh53q5PXPkLsy2kRaqgwoS6YZBLatRZRyUeAkRPe1kLR1P6Mn7jUrXFquUt
|
||||
----
|
||||
====
|
||||
@ -857,8 +882,13 @@ A pay-to-script hash address is created from a transaction script, which defines
|
||||
script hash = RIPEMD160(SHA256(script))
|
||||
----
|
||||
|
||||
((("script hashes")))The resulting "script hash" is encoded with Base58Check with a version prefix of 5, which results in an encoded address starting with a +3+. An example of a P2SH address is +32M8ednmuyZ2zVbes4puqe44NZumgG92sM+.
|
||||
((("script hashes")))The resulting "script hash" is encoded with Base58Check with a version prefix of 5, which results in an encoded address starting with a +3+. An example of a P2SH address is +3F6i6kwkevjR7AsAd4te2YB2zZyASEm1HM+, which can be derived using the Bitcoin Explorer commands((("Bitcoin Explorer","script-encode command")))((("script-encode command (bx)"))) +script-encode+,((("Bitcoin Explorer","sha256 command")))((("sha256 command (bx)"))) +sha256+,((("Bitcoin Explorer","ripemd160 command")))((("ripemd160 command (bx)"))) +ripemd160+ and((("Bitcoin Explorer","base58check-encode command")))((("base58check-encode command (bx)"))) +base58check-encode+ (see <<libbitcoin>>) as follows:
|
||||
|
||||
----
|
||||
$ echo dup hash160 [ 89abcdefabbaabbaabbaabbaabbaabbaabbaabba ] equalverify checksig > script
|
||||
$ bx script-encode < script | bx sha256 | bx ripemd160 | bx base58check-encode --version 5
|
||||
3F6i6kwkevjR7AsAd4te2YB2zZyASEm1HM
|
||||
----
|
||||
|
||||
[TIP]
|
||||
====
|
||||
|
@ -3,8 +3,10 @@
|
||||
int main()
|
||||
{
|
||||
// Private secret key.
|
||||
bc::ec_secret secret = bc::decode_hash(
|
||||
bc::ec_secret secret;
|
||||
bool success = bc::decode_base16(secret,
|
||||
"038109007313a5807b2eccc082c8c3fbb988a973cacf1a7df9ce725c31b14776");
|
||||
assert(success);
|
||||
// Get public key.
|
||||
bc::ec_point public_key = bc::secret_to_public_key(secret);
|
||||
std::cout << "Public key: " << bc::encode_hex(public_key) << std::endl;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import ecdsa
|
||||
import random
|
||||
import time
|
||||
from ecdsa.util import string_to_number, number_to_string
|
||||
|
||||
# secp256k1, http://www.oid-info.com/get/1.3.132.0.10
|
||||
@ -37,6 +38,9 @@ def get_point_pubkey_uncompressed(point):
|
||||
'%064x' % point.y()
|
||||
return key.decode('hex')
|
||||
|
||||
# Seed random number generator.
|
||||
random.seed(time.time())
|
||||
|
||||
# Generate a new private key.
|
||||
secret = random_secret()
|
||||
print "Secret: ", secret
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <bitcoin/bitcoin.hpp>
|
||||
|
||||
bc::hash_digest create_merkle(bc::hash_digest_list& merkle)
|
||||
bc::hash_digest create_merkle(bc::hash_list& merkle)
|
||||
{
|
||||
// Stop if hash list is empty.
|
||||
if (merkle.empty())
|
||||
@ -18,7 +18,7 @@ bc::hash_digest create_merkle(bc::hash_digest_list& merkle)
|
||||
assert(merkle.size() % 2 == 0);
|
||||
|
||||
// New hash list.
|
||||
bc::hash_digest_list new_merkle;
|
||||
bc::hash_list new_merkle;
|
||||
// Loop through hashes 2 at a time.
|
||||
for (auto it = merkle.begin(); it != merkle.end(); it += 2)
|
||||
{
|
||||
@ -50,10 +50,10 @@ bc::hash_digest create_merkle(bc::hash_digest_list& merkle)
|
||||
int main()
|
||||
{
|
||||
// Replace these hashes with ones from a block to reproduce the same merkle root.
|
||||
bc::hash_digest_list tx_hashes{{
|
||||
bc::decode_hash("0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
bc::decode_hash("0000000000000000000000000000000000000000000000000000000000000011"),
|
||||
bc::decode_hash("0000000000000000000000000000000000000000000000000000000000000022"),
|
||||
bc::hash_list tx_hashes{{
|
||||
bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000011"),
|
||||
bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000022"),
|
||||
}};
|
||||
const bc::hash_digest merkle_root = create_merkle(tx_hashes);
|
||||
std::cout << "Result: " << bc::encode_hex(merkle_root) << std::endl;
|
||||
|
@ -123,7 +123,7 @@ During the development of the book, I made early drafts available on GitHub and
|
||||
|
||||
Once the book was drafted, it went through several rounds of technical review. Thanks to Cricket Liu and Lorne Lantz for their thorough review, comments, and support.
|
||||
|
||||
Several bitcoin developers contributed code samples, reviews, comments, and encouragement. Thanks to Amir Taaki for example code snippets and many great comments; Vitalik Buterin and Richard Kiss for help with elliptic curve math and code contributions; Gavin Andresen for corrections, comments, and encouragement; and Michalis Kargakis for comments, contributions, and btcd writeup.
|
||||
Several bitcoin developers contributed code samples, reviews, comments, and encouragement. Thanks to Amir Taaki and Eric Voskuil for example code snippets and many great comments; Vitalik Buterin and Richard Kiss for help with elliptic curve math and code contributions; Gavin Andresen for corrections, comments, and encouragement; and Michalis Kargakis for comments, contributions, and btcd writeup.
|
||||
|
||||
I owe my love of words and books to my mother, Theresa, who raised me in a house with books lining every wall. My mother also bought me my first computer in 1982, despite being a self-described technophobe. My father, Menelaos, a civil engineer who just published his first book at 80 years old, was the one who taught me logical and analytical thinking and a love of science and engineering.
|
||||
|
||||
@ -155,4 +155,4 @@ Many contributors offered comments, corrections, and additions to the early-rele
|
||||
* Stephan Oeste (Emzy)
|
||||
* Joe Bauers (joebauers)
|
||||
* Jason Bisterfeldt (jbisterfeldt)
|
||||
* Ed Leafe (EdLeafe)
|
||||
* Ed Leafe (EdLeafe)
|
||||
|
Loading…
Reference in New Issue
Block a user