[TOC]
比特幣介紹
歷史
比特幣(bitcoin)由中本聰于2009年提出并開源。它具有分布式、去中心化、加密數字化等特點,采用工作量證明機制解決共識問題,所以,它又是安全的。
它誕生與全球經濟危機(2008年)時期,是奧地利經濟學派觀點的實踐。
比特幣定義
通常所說的比特幣指的是一種加密數字貨幣,由比特幣網絡發行(實際是給礦工的獎勵)、并在比特幣網絡上流通。數字簽名是目前數字貨幣的首選方案,其可以有效驗證貨幣所有權。對于雙清問題,比特幣采用工作量證明機制解決雙清問題。
交易
交易是參與者之間價值轉移的過程。
比特幣交易的基礎單元是交易輸出。未被使用的輸出被稱為UTXO。一個UTXO是最小的不可分割的。一個UTXO是一聰(satoshi)的任意整數倍。
密鑰及比特幣地址
比特幣采用公鑰加密方案對交易進行簽名,算法為橢圓曲線乘法算法。交易通常會包含一個公鑰、數字簽名和地址。
私鑰、公鑰、比特幣地址三者間關系,如下圖:
[圖片上傳失敗...(image-31ce69-1520689362124)]
私鑰
比特幣對私鑰并沒有強制規定。用戶可以自行選擇私鑰。私鑰目前是一個256位的數字,通常從一個安全的隨機數序列中產生。加密安全的偽隨機數生成器推薦使用CSPRNG。生成一個私鑰的通常流程為:選擇隨機數生成器->選擇隨機數種子->生成一個隨機數->SHA256哈希算法生成256位的數。
使用比特幣客戶端生成私鑰的方法如下:
$ bitcoin-cli getnewaddress
1J7mdg5rbQyUHENYdx39WVWK7fsLpEoXZy
$ bitcoin-cli dumpprivkey 1J7mdg5rbQyUHENYdx39WVWK7fsLpEoXZy
KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ
或者使用bitcoin explorer的cli工具:
$ bx seed | bx ec-new | bx ec-to-wif
5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
比特幣私鑰通常使用WIF(Wallet Import Format)顯示私鑰。
公鑰
Public Key是從私鑰計算而來的,計算方法采用橢圓曲線密碼學的第二個標準secp256k1。
生成公式:
K = k * G
k為私鑰。K為生成的公鑰。G為預定義的點(被稱為generator point G)。k * G生成曲線上的另外一個點,該點即為公鑰K。
比特幣地址
根據公鑰生成的比特幣地址以數字1開頭。生成公式為:
A = RIPEMD160(SHA256(K))
上述公式生成的地址A為160位,共20個字節。比特幣通常使用Base58Check編碼格式編碼比特幣地址A。
Base58的詳情信息參見鏈接。
Base58Check的過程如下:
Bitcoin Address = PREFIX + A + Checksum
checksum = sha256(sha256(PREFIX + A)
prefix定義
Type | Version Prefix(Hex) | Base58 result prefix |
---|---|---|
Bitcoin Address | 0x00 | 1 |
Pay-to-Script-Hash Address | 0x05 | 3 |
Bitcoin Testnet Address | 0x6F | m or n |
Private Key WIF | 0x80 | 5,K, or L |
BIP-38 Encrypted Private Key | 0x0142 | 6P |
BIP-32 Extended Public Key | 0x0488B21E | xpub |
私鑰的編碼格式
Type | Prefix | 描述 |
---|---|---|
Raw | None | 32字節 |
Hex | None | 64個16進制數字 |
WIF | 5 | Base58Check |
WIF-compressed | K or L | As above, with added suffix 0x01 before encoding |
BIP-38 | 6P | BIP-38標準加密的私鑰 |
密鑰和地址強化
加密密鑰
BIP-38標準是一個通用的私鑰加密標準。它使用AES加密算法。用戶需要提供私鑰和一個passphrase。BIP-38標準生成的私鑰以6P開頭。
P2SH和多簽名地址
P2SH全稱為Pay-to-Script Hash,又稱為Multisig Addresses(多重簽名地址),地址前輟為3。目前,最為普遍的P2SH功能應用是多簽名地址腳本。這種腳本要求用戶提供一到多個簽名來證明控制權(Ownership),然后才可以花費這筆資金。
生成P2SH地址的過程一般如下:
graph LR
A[script]-->B(script-encode)
B --> C(sha256)
C --> D(ripemd160)
D --> E(base58check-encode)
代碼示例如下
$ echo \
'DUP HASH160 [89abcdefabbaabbaabbaabbaabbaabbaabbaabba] EQUALVERIFY CHECKSIG' > script
$ bx script-encode < script | bx sha256 | bx ripemd160 \
| bx base58check-encode --version 5
3F6i6kwkevjR7AsAd4te2YB2zZyASEm1HM
靚號地址(Vanity Addresses)
靚號地址是一個有效的比特幣地址,它含有一部分有意義的信息。如地址1LoveBPzzD72PUXLzCkYAtGFYmK5vYNR33
。該地址包含詞"Love"。
紙錢包
所謂紙錢包就是把私鑰和地址打印一張紙上。這是一種廉價的離線存儲手段。離線存儲的錢包也叫冷錢包。直接將私鑰原樣做成紙錢包并不安全(盜賊)。通常,冷存儲的是BIP-38加密過的私鑰。這就要求用戶要記住一個passphrase或將passphrase另行存儲。
錢包
錢包(wallet)是一個應用程序,用于管理密鑰、地址,跟蹤余額以及簽名交易。
從技術的角度來看,錢包是一種數據結構,用于存儲和管理用戶的密鑰。
小提示:比特幣錢包并不含有比特幣,他只包含密鑰。所謂的幣是記錄在比特幣網絡的區塊鏈里的,'幣'是交易輸出的一種形式(通常稱為vout或txout)。
錢包有兩種類型:非確定性錢包和確定性錢包。區分的標準是密鑰間是否有關聯。
非確定性錢包里的密鑰們沒有相關性,是獨立的。
確定性錢包里的密鑰由一個主私鑰衍生而來(被稱為seed,即種子)。最常見的實現方式是一種類樹狀結構,被稱為分層確定性錢包(HD wallet),標準為BIP-32/BIP-44。
確定性錢包從一個種子初始化而來。為便于使用,種子通常編碼為英文單詞,又稱助記碼(Mnemonic Codes,標準為BIP-39)。
現在,基本上都是HD錢包了,除了Bitcoin core。
錢包最佳實踐
- 基于BIP-39的助記碼
- 基于BIP-32的HD錢包
- 基于BIP-43的多用途HD錢包
- 基于BIP-44的多幣種、多帳號錢包
助記符(BIP-39)
BIP-39是助記碼的當前工業標準。它是Trezor硬件錢包公司提出的。目前,BIP-39有兩個實現版本:Trezor版本和Electrum錢包。兩者因為使用不同的詞典集合而不能互通。
助記符生成示例如下
$bx mnemonic-new ea3138a05e18f4f68f345a40b0e4e264
tuition mean chimney rotate monster kitten devote mercy doll mango decade since
交易
交易是比特幣系統最重要的部分。系統的其他部分都是為了保證交易的創建、驗證以及記入全球帳薄。
交易輸出和輸入
比特幣交易的基石是交易輸出(vout)。交易輸出是不可分割的比特幣貨幣(類似于有面額的紙幣),記錄在區塊鏈上并由全網絡驗證有效。比特幣全節點跟蹤所有的可用、可花費的輸出,這些輸出被稱為UTXO(未花費的交易輸出)。
原始的交易解碼后,一般是下面樣子:
{
"version": 1,
"locktime": 0,
"vin": [
{
"txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
"vout": 0,
"scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
"sequence": 4294967295
}
],
"vout": [
{
"value": 0.01500000,
"scriptPubKey": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG"
},
{
"value": 0.08450000,
"scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
}
]
}
每一個區塊的第一個交易被稱為coinbase交易,即比特幣網絡給礦工的獎勵。所以,coinbase交易是沒有input的。
交易輸出
交易輸出包括兩部分:
- 一定量的比特幣,單位是聰(satoshis)
- 一個加密迷題(花費該UTXO的必要條件),又被稱為鎖定腳本(locking script)、見證腳本(witness script)或scriptPubKey。
輸出的序列化結構(開發人員關注)
Size | Field | Description |
---|---|---|
8 bytes(小端) | 總量 | 比特幣總量,單位聰(satoshis) |
1-9 bytes | Locking Script的大小 | Locking Script的字節大小 |
可變部分 | Locking Script | 定義花出該輸出的前提條件的腳本 |
交易輸入
交易輸入標識哪個UTXO將被消費(花出)并通過unlocking script證明其所有權。
其主要包含如下幾部分:
- 一個交易id, txid
- 一個UTXO的索引(從0開始)
- 一個scriptSig,用于unlocking花費
- 一個序列號
示例如下:
"vin": [
{
"txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
"vout": 0,
"scriptSig" : "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
"sequence": 4294967295
}
]
交易費
大部分交易是包含交易費的。交易費用于激勵礦工維護比特幣網絡。交易費用是隱含在交易中的,其數值為Fees = Sum(Inputs) – Sum(Outputs)
。
交易腳本
比特幣的交易腳本(script)是一種類似于Forth語言的、逆波蘭式、基于堆棧的語言。
比特幣的腳本語言不是圖靈完備的,不支持loop操作
比特幣腳本語言是無狀態的
比特幣腳本語言簡單,但并不友好。看起來,像是匯編語言
腳本構建
比特幣交易驗證引擎依賴于兩種腳本:一個鎖定腳本和一個解鎖腳本。
鎖定腳本通常稱為scriptPubKey。解鎖腳本通常稱為scriptSig。
交易驗證時,引擎執行流程是:scriptSig -> scriptPubKey。
示例如下:
[圖片上傳失敗...(image-ec046-1520689362124)]
具體執行流程如下:
[圖片上傳失敗...(image-ec5c92-1520689362124)]
數字簽名
比特幣使用的數字簽名算法為ECDSA。該算法是一種公鑰加密算法。
數字簽名有三個作用:
- 所有權證明
- 授權是不可否認的(即交易一旦生成,不可否認)
- 一旦簽名,則交易不可修改(或特定部分不可修改)
高級交易和腳本
隔離見證的核心部分
比特幣網絡
區塊鏈
區塊鏈數據結構是一種后向鏈接的有序鏈表。比特幣客戶端使用Google LevelDB存儲區塊鏈的元數據。
Block數據結構
Block Structure
Size | Field | Description |
---|---|---|
4字節 | 塊大小 | 隨后的塊大小,字節單位 |
80 bytes | Block Header | 由多個field構成 |
1–9 bytes (VarInt) | 交易計數器 | 該block包含的交易數目 |
可變部分 | 交易的集合 | 記錄在該區塊上的交易 |
區塊頭(Block Header)
Size | Field | Description |
---|---|---|
4 bytes | Version | 協議的版本號 |
32 bytes | Previous Block Hash | 父區塊的Hash |
32 bytes | Merkle Root | Merkle樹的root |
4 bytes | 時間戳 | 區塊的創建時間,秒(是個近似值) |
4 bytes | Difficulty Target(難度目標) | 該區塊的PoW難度 |
4 bytes | Nonce | PoW算法的一個計數器 |
區塊標識 (Block Identifier)
Block的標識是一個哈希值(Hash),使用sha256算法對區塊頭(Block Header)執行兩次哈希操作而來。
創世區塊的哈希值是:000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
區塊的Hash值并沒有存儲在區塊上。當節點收到一個區塊時,節點需要去計算該節點的Hash。
另一種標識則是區塊高度(block height)。創世區塊從0開始。一個區塊一定有一個高度。但一個高度并不唯一對應一個區塊。這涉及到區塊競爭問題。常見場景是forks(即分叉)。Block Height也不是區塊數據結構的一部分。節點需要在收到區塊時計算。
創世區塊(Genesis Block)
比特幣區塊鏈上的第一個區塊被稱為創世區塊,創建于2009年。它是所有區塊的祖宗。創世區塊的UTXO是50BTC,至今未花。創世區塊上寫有一條信息(已經是非常出名了):"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks."。
Merkle Tree
每一個區塊均使用Merkle Tree記錄該區塊上所有交易的摘要。Merkle Tree生成過程如下圖所示。
[圖片上傳失敗...(image-79a62-1520689362124)]
區塊上存儲Merkle Tree Root節點的hash。每個節點的hash算法均為double-sha256。
SPV (Simplifiled Payment Verification)
SPV節點不需要全部的交易數據也不需要下載全部區塊,只需要區塊頭數據即可。SPV節點使用merkle path來驗證一個節點是否被包含在該區塊內。
SPV節點驗證交易A被包含于區塊Block_b的基本過程如下:
- SPV節點向向周邊節點(peers)廣播其感興趣的交易(以bloom filter形式)
- 當一個peer節點發現一條交易包含在bloom filter中,該節點則返回該區塊(區塊頭和一條merkle path)
- SPV節點使用merkle path驗證交易A是否在Block_b中
merkle path如下圖所示:
[圖片上傳失敗...(image-26d469-1520689362124)]
如果要驗證交易Hk是否包含在區塊內,只需要獲知H(L), H(IJ), H(MNOP),H(ABCDEFGH)這四個哈希值即可。
Merkle Tree的效率
交易數量 | 區塊大小 | Merkle Path哈希數 | Path字節數 |
---|---|---|---|
16條交易 | 4KB | 4 hashes | 128B |
512條交易 | 128KB | 9 hashes | 288B |
2048條交易 | 512KB | 11 hashes | 352B |
65535條交易 | 16MB | 16 hashes | 512B |
比特幣測試鏈(Test Blockchains)
比特幣是有多條鏈的。由中本聰同學創建于2009年1月3日的區塊鏈為主網絡(mainnet
)。還有其他測試目的的區塊鏈:testnet(測試網絡), segnet(隔離見證網絡), regtest。
- testnet
testnet擁有主網絡的所有特征。通常,testnet網絡上的幣是沒有價值的(因為其挖礦難度比較低),但事實并非如此。因為總是有玩家使用asic來挖礦,從而導致測試網絡挖幣也是一件困難的事情。目前的解決方案是從一個新的創世區塊重啟測試網絡,并重設難度。
目前的測試網絡為testnet3(重啟于2011年)。
bitcoind -testnet
- segnet
2016年,為了支持SegNet的開發測試,一個特定目的的測試網絡啟動。(目前已不再是必須的,因為segwit已經被testnet3引入)
- Regtest
本地區塊鏈
$ bitcoind -regtest
挖礦和共識
挖礦是確保比特幣去中心化安全性的機制。比特幣是一種經濟激勵機制。
礦工負責驗證新的交易并記錄在全球帳薄上。挖出一個新區塊的平均時間是10分鐘。而記錄在區塊鏈上的交易則被認為是確認過的。
比特幣的確認時間目前比較長,一個小時之上。
礦工有兩種獎勵:交易費和區塊獎勵。為了獲得獎勵,礦工需要解決一個數學難題。比特幣采用PoW方案來解決這個難題(工作量證明-Proof-of-Work)。答案被記錄在新區塊中并作為一個憑據。該憑據可以證明礦工花費了一定的算力來解決這個問題。
這個過程稱為挖礦,因為獎勵(比特幣發生成)旨在模擬收益遞減,就像開采貴金屬一樣。比特幣總量固定而且區塊生成的比特幣每四年或210000個區塊減半。2009年一個區塊獎勵是50個比特幣,2012年11月為25個比特幣,2016年7月則為12.5個。到2140年,不會再有新的比特幣生成。
目前,交易費只占礦工收入的0.5%。而隨著獎勵指數級下降,區塊上的交易日漸增多,比特幣礦業收入的更大比例將來自交易費用。
從發行上來看,比特幣是具有通縮特性的。