今天的越寫越快樂系列為大家?guī)怼毒ū忍貛拧纷x書筆記之交易章節(jié)的下半部分的分享。
前情回顧
比特幣交易
是比特幣系統(tǒng)中最重要的部分姑荷。根據(jù)比特幣的設(shè)計原理,系統(tǒng)中任何其他的部分都是為了確保比特幣交易可以被生成、能在比特幣網(wǎng)絡(luò)中得以傳播和通過驗證胜榔,并最終加入全球比特幣交易的總賬本(比特幣區(qū)塊鏈)
。
類比現(xiàn)實生活中你去商場買鞋湃番,然后看中一雙鞋夭织,親自試了試,覺得合適吠撮,然后付款尊惰,拿著鞋離開商場,而交易就大致這么個過程,只是交易的渠道和媒介不太一樣罷了
比特幣交易腳本和腳本語言
比特幣交易腳本弄屡,是一種類似Forth的逆波蘭表達式的基于堆棧的執(zhí)行語言题禀。放置在UTXO上的鎖定腳本和解鎖腳本都以此腳本語言編寫。當一筆交易被驗證時膀捷,每一個輸入值中的解鎖腳本與其對應(yīng)的鎖定腳本同時(互不干擾迈嘹,相互隔離)執(zhí)行,以確定這筆交易是否滿足支付條件全庸。
如今江锨,大多數(shù)經(jīng)比特幣網(wǎng)絡(luò)處理的交易是以“Alice付給Bob”的形式存在,并基于一種稱為“P2PKH”腳本糕篇。但是比特幣交易不局限于“支付給Bob的比特幣地址”的腳本啄育。事實上,鎖定腳本可以被編寫成表達各種復(fù)雜的情況拌消。
比特幣交易驗證并不基于靜態(tài)模式挑豌,而是通過腳本語言的執(zhí)行來實現(xiàn)的。這種語言允許表達幾乎無限的各種條件墩崩,這也是比特幣作為一種“可編程貨幣”所擁有的力量氓英。
圖靈非完備性
比特幣腳本語言包含許多操作碼,但都故意限定為一種重要的模式——除了有條件的流控制以外鹦筹,沒有任何循環(huán)或者復(fù)雜流控制能力铝阐。這樣就保證了腳本語言的圖靈非完備性,這就意味著腳本有限的復(fù)雜性和可預(yù)見的執(zhí)行次數(shù)铐拐。
圖靈非完備性是不能解決所有的可計算性問題的通用物理機器或編程語言徘键。
去中心化驗證
由于比特幣系統(tǒng)是去中心化的,因此沒有任何一個節(jié)點可以控制其他節(jié)點的交易腳本的執(zhí)行遍蟋,那么對于腳本的執(zhí)行吹害,只有包含執(zhí)行腳本的所有信息,執(zhí)行腳本才能順利地完成執(zhí)行虚青。這樣的話它呀,同一個執(zhí)行腳本可以在任意一個節(jié)點上執(zhí)行,得到相同的執(zhí)行結(jié)果棒厘。
可以聯(lián)想到函數(shù)的冪等性纵穿,也就是函數(shù)的執(zhí)行結(jié)果和其執(zhí)行的次數(shù)無關(guān)。具體有關(guān)冪等性的解釋奢人,請參考理解HTTP冪等性
腳本構(gòu)建
比特幣的交易驗證引擎依賴于兩類腳本來驗證比特幣交易:鎖定腳本和解鎖腳本谓媒。鎖定腳本是一個放置在輸出上面的花費條件:它指定了今后花費這邊輸出必須滿足的條件。解鎖腳本是一個“解決”或滿足被鎖定腳本在一個輸出上設(shè)定的花費條件的腳本达传,它允許輸出被消費篙耗。解鎖腳本是每一個比特幣交易輸入的一部分迫筑,而且往往含有一個由用戶的比特幣錢包(通過私鑰)生成的數(shù)字簽名。
每一個比特幣驗證節(jié)點會通過同時執(zhí)行鎖定腳本和解鎖腳本來驗證一筆交易宗弯。每一個輸入都包含一個解鎖腳本脯燃,并引用了之前存在的UTXO。驗證軟件將復(fù)制解鎖腳本蒙保,檢索輸入引用的UTXO辕棚,并從該UTXO復(fù)制鎖定腳本。然后依次很自信解鎖和鎖定腳本邓厕。如果解鎖腳本滿足鎖定腳本條件逝嚎,則輸入有效。所有的輸入都是獨立驗證的详恼,作為交易總體驗證的一部分补君。
腳本執(zhí)行堆棧
腳本執(zhí)行堆棧用于執(zhí)行操作腳本,也就是由操作數(shù)和操作碼構(gòu)成的操作表達式昧互。堆棧是一個非常簡單的數(shù)據(jù)結(jié)構(gòu)挽铁,可以被視為一疊卡片。棧允許兩個操作:push和pop敞掘。Push(推送)在堆棧頂部添加一個項目叽掘。Pop(彈出)從堆棧中刪除最頂端的一個項目。棧的操作只能作用于棧的頂端項目玖雁。
腳本語言通過從左到右處理每個項目來執(zhí)行腳本更扁。先把操作數(shù)推倒堆棧,然后操作碼從堆棧中推送或者彈出一個或多個參數(shù)赫冬,對其進行操作浓镜,并可能將結(jié)果推送到堆棧上。
從左到右的執(zhí)行順序有沒有讓你想到哪種計算機編程語言呢面殖?
這種操作數(shù)和操作碼的方式可以聯(lián)想到計算機的匯編語言竖哩,匯編語言的簡單入門,請參考阮一峰老師的匯編語言入門脊僚。
腳本語言可以看作比特幣系統(tǒng)中一段可以自動執(zhí)行的程序,該程序用在比特幣系統(tǒng)中的大部分場合遵绰,結(jié)合本書附錄的第二部分腳本語言操作費辽幌、常量和符號,我相信你對交易腳本會有一個比較深入的認識椿访。
腳本一個簡單腳本示例
鎖定腳本如下
3 OP_ADD 5 OP_EQUAL
解鎖腳本如下
2
鎖定和解鎖腳本組合乌企,其結(jié)果腳本如下
2 3 OP_ADD 5 OP_EQUAL
上述腳本的含義是操作數(shù)2和3進行相加操作,然后OP_EQUAL操作碼驗證相加的結(jié)果是否為5成玫。當腳本執(zhí)行后加酵,如果執(zhí)行結(jié)果是OP_TRUE拳喻,則說明交易有效。不僅該筆的輸出鎖定腳本有效猪腕,同時UTXO也能被任何知曉這個運算技巧的人所使用冗澈。
每次腳本執(zhí)行完成后都會查看棧頂?shù)慕Y(jié)果是否為TRUE,如果堆棧頂部的結(jié)果顯示為FALSE陋葡,或者腳本執(zhí)行被操作碼明確禁止亚亲,或有條件終止,則交易無效腐缤。有沒有聯(lián)想到以太坊的溢出安全問題捌归,其實就是沒有充分考慮軟件執(zhí)行條件的邊界問題,當然以太坊的安全漏洞不是我說的這么簡單??岭粤。
交易執(zhí)行結(jié)果腳本請參考相關(guān)章節(jié)內(nèi)容惜索。
解鎖和鎖定腳本的單獨執(zhí)行
可以看作你向朋友轉(zhuǎn)賬時,需要驗證雙方的有效身份并檢索賬戶余額剃浇,然后發(fā)起轉(zhuǎn)賬操作门扇。
將解鎖和鎖定腳本分別傳遞給堆棧執(zhí)行引擎,具體的執(zhí)行過程如下:首先偿渡,使用堆棧執(zhí)行引擎執(zhí)行解鎖腳本臼寄,如果解鎖腳本在執(zhí)行過程中未報錯,則負責主堆棧溜宽,并執(zhí)行鎖定腳本吉拳。如果從解鎖腳本中復(fù)制過來的堆棧數(shù)據(jù)執(zhí)行鎖定腳本的結(jié)果為“TRUE”,那么解鎖腳本就成功地滿足了鎖定腳本所設(shè)置的條件适揉。因此該輸入是一個能使用該UTXO的有效授權(quán)留攒。如果在合并腳本后的結(jié)果不是“TRUE”以外的任何結(jié)果,輸入都是無效的嫉嘀,因為它不滿足UTXO中所設(shè)置的使用該筆資金的條件炼邀。
可以看作在轉(zhuǎn)賬的過程中驗證不通過,可能出現(xiàn)的問題有余額不足剪侮、身份欺詐拭宁、網(wǎng)絡(luò)不通暢等。
P2PKH(Pay-to-Public-Key-Hash)
比特幣網(wǎng)絡(luò)處理的大多數(shù)交易花費的都是“付款至公鑰哈习旮”腳本鎖定的輸出杰标,這些輸出都含有一個鎖定腳本,將輸入鎖定為一個公鑰哈希值彩匕,即我們常說的比特幣地址腔剂。由P2PKH腳本鎖定的輸出可以通過提供一個公鑰和由相應(yīng)私鑰創(chuàng)建的數(shù)字簽名來解鎖。例如驼仪,我們可以再次回顧一下Alice向Bob咖啡館支付的案例掸犬。Alice下達了向Bob咖啡館的比特幣地址支付了0.015比特幣的支付指令袜漩,該筆交易的輸出內(nèi)容為以下形式的鎖定腳本:
OP_DUP OP_HASH160 <Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG
腳本中的Cafe Public Key Hash 即為咖啡館的比特幣地址,但該地址不是基于Base58Check編碼湾碎。事實上宙攻,大多數(shù)比特幣地址的公鑰哈希值都顯示為十六進制碼,而不是大家所熟知的以1開頭的基于Base58Check編碼的比特幣地址胜茧。上述鎖定腳本相應(yīng)的解鎖腳本是:
<Cafe Signature> <Cafe Public Key>
將兩個腳本結(jié)合起來可以形成如下組合驗證腳本:
<Cafe Signature> <Cafe Public Key> OP_DUP OP_HASH160
<Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG
只有當解鎖腳本與鎖定腳本的設(shè)定條件相匹配時粘优,執(zhí)行組合驗證腳本才會顯示結(jié)果為TRUE。換句話說呻顽,只有當解鎖腳本得到了咖啡館的有效簽名雹顺,交易執(zhí)行結(jié)果才會被通過,該有效簽名是從與公鑰哈希相匹配的咖啡館的私鑰中所獲取的廊遍。
其實就是驗證接收者的簽名是否與發(fā)送者給定的轉(zhuǎn)賬地址匹配嬉愧,簡單的理解就是《林海雪原》中的那句
天王蓋地虎,寶塔鎮(zhèn)河妖
喉前。
數(shù)字簽名
比特幣中石油的數(shù)字簽名算法是橢圓曲線數(shù)字簽名算法(ECDSA)没酣。ECDSA是用于基于橢圓曲線私鑰/公鑰對的數(shù)字簽名算法。ECDSA用于腳本函數(shù)OP_CHECKSIG卵迂,OP_CHECKSIGVERIFY裕便,OP_CHECKMULTISIG和OP_CHECKMULTISIGVERIFY。每當你鎖定腳本看到這些腳本函數(shù)式见咒,解鎖腳本都必須包含一個ECDSA簽名偿衰。
數(shù)字簽名在比特幣中的用途:
簽名證明私鑰的所有者,即資金所有者改览,已經(jīng)授權(quán)支出這些資金下翎;
授權(quán)證明是不可否認的;
簽名證明交易在簽字之后沒有也不能被任何人修改宝当。
數(shù)字簽名如何工作
數(shù)字簽名是一種由兩部分組成的數(shù)學方案:第一部分是使用私鑰從消息(交易)創(chuàng)建簽名的算法视事;第二部分是允許任何人驗證簽名的算法,給定消息和公鑰庆揩。
在比特幣的ECDSA算法的實現(xiàn)中俐东,被簽名的“消息”是交易,或更確切地說是交易中特定數(shù)據(jù)子集的哈希值盾鳞。簽名密鑰是用戶的私鑰犬性,結(jié)果是簽名,公式如下:
((Sig = F{sig}(F{hash}(m), dA)))
腾仅。
公式中的字母含義如下:
- dA 是簽名私鑰
- m 是交易(或其部分)
- Fhash 是散列函數(shù)
- Fsig 是簽名算法
- Sig 是結(jié)果簽名
ECDSA數(shù)學運算的更多細節(jié)可以在ECDSA Math章節(jié)中找到。函數(shù)Fsig 產(chǎn)生由兩個值組成的簽名Sig套利,通常稱為R和S:Sig = (R, S)
⊥评現(xiàn)在已經(jīng)計算了兩個值R和S鹤耍,它們就序列化為字節(jié)流,使用一種稱為“分辨編碼規(guī)則”(Distinguished Encoding Rules)或 DER的國際標準編碼方案验辞。
接下來我們看看簽名序列化稿黄,也就是DER的過程,我們來看看Alice創(chuàng)建的交易跌造。 在交易輸入中有一個解鎖腳本杆怕,其中包含Alice的錢包中的以下DER編碼簽名:
3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e381301
該簽名是Alice的錢包生成的R和S值的序列化字節(jié)流,證明她擁有授權(quán)花費該輸出的私鑰壳贪。 序列化格式包含以下9個元素:
- 0x30表示DER序列的開始
- 0x45 - 序列的長度(69字節(jié))
- 0x02 - 一個整數(shù)值
- 0x21 - 整數(shù)的長度(33字節(jié))
- R-00884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb
- 0x02 - 接下來是一個整數(shù)
- 0x20 - 整數(shù)的長度(32字節(jié))
- S-4b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813
- 后綴(0x01)指示使用的哈希的類型(SIGHASH_ALL)
看看您是否可以使用此列表解碼 Alice 的序列化(DER編碼)簽名陵珍。 重要的數(shù)字是R和S; 數(shù)據(jù)的其余部分是DER編碼方案的一部分。
驗證簽名
要驗證簽名违施,必須有簽名(R和S)互纯、序列化交易和公鑰(對應(yīng)于用于創(chuàng)建簽名的私鑰)。本質(zhì)上磕蒲,簽名的驗證意味著“只有生成此公鑰的私鑰的所有者留潦,才能在此交易上產(chǎn)生此簽名±蓖”
簽名驗證算法采用消息(交易或其部分的哈希值)兔院、簽名者的公鑰和簽名(R和S值),如果簽名對該消息和公鑰有效站削,則返回 TRUE 值坊萝。
簽名哈希類型(SIGHASH)
比特幣簽名具有指示交易數(shù)據(jù)的哪一部分包含在使用 SIGHASH 標志的私鑰簽名的哈希中的方式。 SIGHASH 標志是附加到簽名的單個字節(jié)钻哩。每個簽名都有一個SIGHASH標志屹堰,該標志在不同輸入之間也可以不同。具有三個簽名輸入的交易可以具有不同SIGHASH標志的三個簽名街氢,每個簽名簽署(承諾)交易的不同部分扯键。
記住,每個輸入可能在其解鎖腳本中包含一個簽名珊肃。因此荣刑,包含多個輸入的交易可以擁有具有不同SIGHASH標志的簽名,這些標志在每個輸入中承諾交易的不同部分伦乔。還要注意厉亏,比特幣交易可能包含來自不同“所有者”的輸入,他們在部分構(gòu)建(和無效)的交易中可能僅簽署一個輸入烈和,繼而與他人協(xié)作收集所有必要的簽名后再使交易生效爱只。許多SIGHSASH標志類型,只有在你考慮到由許多參與者在比特幣網(wǎng)絡(luò)之外共同協(xié)作去更新僅部分簽署了的交易招刹,才具有意義恬试。
有三個SIGHASH標志:ALL窝趣,NONE和SINGLE,如下表所示训柴。
另外還有一個修飾符標志SIGHASH_ANYONECANPAY哑舒,它可以與前面的每個標志組合。 當設(shè)置ANYONECANPAY時幻馁,只有一個輸入被簽名洗鸵,其余的(及其序列號)打開以進行修改。 ANYONECANPAY的值為0x80仗嗦,并通過按位OR運算膘滨,得到如下所示的組合標志:
SIGHASH標志在簽名和驗證期間應(yīng)用的方式是建立交易的副本和刪節(jié)其中的某些字段(設(shè)置長度為零并清空),繼而生成的交易被序列化儒将,SIGHASH標志被添加到序列化交易的結(jié)尾吏祸,并將結(jié)果哈希化 钩蚊,得到的哈希值本身即是被簽名的“消息”贡翘。 基于SIGHASH標志的使用,交易的不同部分被刪節(jié)砰逻。 所得到的哈希值取決于交易中數(shù)據(jù)的不同子集鸣驱。 在哈希化前蝠咆,SIGHASH作為最后一步被包含在內(nèi)踊东,簽名也會對SIGHASH類型進行簽署,因此不能更改刚操。
ECDSA數(shù)學
簽名算法首先生成一個 ephemeral(臨時)私公鑰對闸翅。 在涉及簽名私鑰和交易哈希的變換之后,該臨時密鑰對用于計算R和S值菊霜。臨時密鑰對基于隨機數(shù)k坚冀,用作臨時私鑰。 從k鉴逞,我們生成相應(yīng)的臨時公鑰P记某。數(shù)字簽名的R值則是臨時公鑰P的x坐標。從那里构捡,算法計算簽名的S值液南,使得:
其中:
- k是臨時私鑰
- R是臨時公鑰的x坐標
- dA是簽名私鑰
- m是交易數(shù)據(jù)
- p是橢圓曲線的主要順序
驗證是簽名生成函數(shù)的倒數(shù),使用R勾徽,S值和公鑰來計算一個值P滑凉,該值是橢圓曲線上的一個點(簽名創(chuàng)建中使用的臨時公鑰):
其中:
- R和S是簽名值
- Qa是Alice的公鑰
- m是簽署的交易數(shù)據(jù)
- G是橢圓曲線發(fā)生器點
如果計算點P的x坐標等于R,則驗證者可以得出結(jié)論,簽名是有效的譬涡。
隨機性在簽名中的重要性
如我們在ECDSA Math中所看到的闪幽,簽名生成算法使用隨機密鑰k作為臨時私有-公鑰對的基礎(chǔ)啥辨。 k 的值不重要涡匀,只要它是隨機的。如果使用相同的值 k 在不同的消息(交易)上產(chǎn)生兩個簽名溉知,那么簽名私鑰可以由任何人計算陨瘩。在簽名算法中重用相同的 k 值會導(dǎo)致私鑰的暴露。
比特幣地址级乍、余額和其他摘要
在上圖中表示的是最近發(fā)生的一筆交易舌劳,該交易在區(qū)塊鏈瀏覽器上的交易記錄。在交易的左側(cè)玫荣,區(qū)塊鏈瀏覽器將比特幣地址18T6vFXeCr7evfXCNz6bfqeJ7QiPi3AZi7
顯示為“發(fā)送者”甚淡,其實這個信息本身并不在交易中。當區(qū)塊鏈接到瀏覽器檢索到交易時捅厂,它還檢索在輸入中引用的先前交易贯卦,并從該舊交易中提取第一個輸出。在該輸出內(nèi)是一個鎖定腳本焙贷,將UTXO鎖定到某個人的公鑰哈希(P2PKH腳本)撵割。塊鏈瀏覽器提取公鑰哈希,并使用Base58Check編碼對其進行編碼辙芍,以生成和顯示表示該公鑰的比特幣地址啡彬。同樣,在右側(cè)則顯示了接收者的比特幣地址故硅,該地址也是區(qū)塊鏈瀏覽器從每個輸出中提取鎖定腳本庶灿,將其識別為P2PKH腳本,并從內(nèi)部提取公鑰哈希吃衅,最后塊鏈瀏覽器重新編碼了使用Base58Check的公鑰哈希生成和顯示比特幣地址往踢。
對于一個比特幣地址的余額,比特幣系統(tǒng)中沒有余額的概念捐晶,這里顯示的余額是通過以下步驟來顯示在區(qū)塊鏈瀏覽器上的:
- 區(qū)塊鏈瀏覽器解碼比特幣地址的Base58Check編碼菲语,以檢索編碼在地址中的某個用戶X的160位哈希值;
- 區(qū)塊鏈瀏覽器搜索交易數(shù)據(jù)庫,使用包含用戶X公鑰哈希的P2PKH鎖定腳本尋找輸出惑灵,通過總結(jié)所有輸出的值山上,瀏覽器可以產(chǎn)生接收的總值,也就是該用戶X的比特幣地址中顯示的余額英支。
通過計算UTXO集佩憾,區(qū)塊鏈瀏覽器總結(jié)了引用賬戶X的公鑰哈希的所有未使用的值,并產(chǎn)生向用戶顯示的“最終余額”數(shù)目。
引用
個人感想
通過對《精通比特幣》交易章節(jié)的梳理妄帘,我們知道了比特幣交易過程中數(shù)字簽名和交易腳本是如何保證交易的執(zhí)行和確認的楞黄,也讓我聯(lián)想到了現(xiàn)實生活中從最初的銀行轉(zhuǎn)賬匯款、到后來的ATM取現(xiàn)抡驼、到現(xiàn)在的手機銀行轉(zhuǎn)賬鬼廓,隨著支付渠道的興起和支付手段的便捷,讓我們更加意識到了資金安全的重要性致盟,也讓我們知道了比特幣是如何解決我們生活中的需求痛點的碎税,對于跨國結(jié)賬和跨行結(jié)算業(yè)務(wù)有了不一樣的處理渠道,我相信科技和金融的關(guān)系會更加地緊密馏锡,也讓我對金融科技的理解更進一步雷蹂。當然每個國家對于數(shù)字貨幣以及以數(shù)字貨幣為媒介的數(shù)字資產(chǎn)的監(jiān)管政策不同,也誕生了許多數(shù)字貨幣相關(guān)的業(yè)務(wù)和行業(yè)創(chuàng)新杯道,我相信這對于區(qū)塊鏈行業(yè)的發(fā)展匪煌,或者說對于金融行業(yè)和科技行業(yè)的深度整合提供了不一樣的視角和維度。我更堅信區(qū)塊鏈技術(shù)重構(gòu)了生產(chǎn)關(guān)系
這句話深信不疑党巾。雖然我對經(jīng)濟學萎庭、金融學的了解很粗淺,但是我有興趣去了解和探索生產(chǎn)關(guān)系的改變是如何影響大家的生活和工作的昧港。我更是知道技術(shù)是第一生產(chǎn)力擎椰,更是改變你我生活質(zhì)量的利器,要是加以合理利用创肥,我相信會為我們打開一個更有想象力的世界达舒。相信你對比特幣中的交易腳本和數(shù)字簽名有了一定的了解,接下來我會繼續(xù)為大家?guī)韰^(qū)塊鏈其它章節(jié)的分享叹侄,敬請期待巩搏。若是我的文章對你有所啟發(fā),那將是我莫大的榮幸和巨大的鼓舞趾代。