前言
《最小可行性區(qū)塊鏈設(shè)計(jì)系列》的第一講(http://www.reibang.com/p/af45d43b9c85) 實(shí)現(xiàn)了賬戶和交易模型雛形,具體設(shè)計(jì)思路與比特幣的UTXO有所區(qū)別衡招,更接近于以太坊的設(shè)計(jì)二驰。本文將討論并實(shí)現(xiàn)區(qū)塊鏈交易的簽名與驗(yàn)證功能。
本文的代碼地址:https://github.com/qikh/mini-block-chain/commit/81524fe1b4b9228a67b8fc3551d971a0aa0eae52 (開發(fā)語(yǔ)言為Kotlin稿静,更簡(jiǎn)潔的Java)
正文
第一講中梭冠,Alice向Bob發(fā)送了一筆轉(zhuǎn)賬交易,金額為100元改备。交易模型Transaction包含了發(fā)送方地址控漠、接收方地址、金額和時(shí)間戳悬钳。區(qū)塊鏈的客戶端節(jié)點(diǎn)盐捷,負(fù)責(zé)將這筆交易記錄登帳,并更新Alice和Bob的賬戶余額(balance)默勾。
但是碉渡,區(qū)塊鏈的客戶端如何確認(rèn)這筆交易確實(shí)是Alice本人發(fā)起的呢?我們需要交易簽名(sign)和驗(yàn)證(verify)機(jī)制來(lái)確認(rèn)交易(Transaction)的合法性母剥。
如果我們把交易看作一張支票滞诺,那么發(fā)送方(Alice)必須在這張支票上簽名形导,并且第三方(區(qū)塊鏈節(jié)點(diǎn))可以很容易地驗(yàn)證簽名的真?zhèn)巍lice的私鑰就是她的簽名章铭段,用私鑰對(duì)交易(Transaction)的內(nèi)容(發(fā)送方骤宣、接收方、金額序愚、時(shí)間戳)進(jìn)行簽名憔披。
/**
* 發(fā)送方用私鑰對(duì)交易Transaction進(jìn)行簽名。
*/
fun signTransaction(trx: Transaction, privateKey: PrivateKey): ByteArray {
val signer = Signature.getInstance("SHA256withECDSA")
signer.initSign(privateKey)
val msgToSign = getTransactionContentToSign(trx)
signer.update(msgToSign)
return signer.sign()
}
交易(Transaction)加入數(shù)字簽名(signature)后爸吮,區(qū)塊鏈節(jié)點(diǎn)可以用Alice的公鑰來(lái)驗(yàn)證交易是不是Alice發(fā)送出來(lái)的芬膝,驗(yàn)證成功后才會(huì)記錄該筆交易。
/**
* 驗(yàn)證交易Transaction簽名的有效性形娇。
*/
fun verifyTransactionSignature(trx: Transaction, signature: ByteArray, publicKey: PublicKey): Boolean {
val signer = Signature.getInstance("SHA256withECDSA")
signer.initVerify(publicKey)
signer.update(getTransactionContentToSign(trx))
return signer.verify(signature)
}
注意:簽名的交易內(nèi)容應(yīng)該統(tǒng)一序列化算法锰霜,確保內(nèi)容的二進(jìn)制一致性,這樣不同語(yǔ)言的客戶端軟件才能夠驗(yàn)證簽名有效性桐早。本文的實(shí)現(xiàn)比較簡(jiǎn)單癣缅,發(fā)送方地址和接收方地址的16進(jìn)制字符串+金額(數(shù)字轉(zhuǎn)文本)+時(shí)間戳(數(shù)字表示的系統(tǒng)時(shí)鐘)。
區(qū)塊鏈節(jié)點(diǎn)驗(yàn)證交易簽名需要發(fā)送方的公鑰哄酝,公鑰并沒有標(biāo)準(zhǔn)的發(fā)布方法友存,通常會(huì)把公鑰增加到交易(Transaction)里。比特幣的協(xié)議把簽名+公鑰組成簽名腳本(Signature Script或sigScripts)陶衅,作為交易(Transaction)的組成部分屡立。由于比特幣和以太坊所用的ECDSA算法有一個(gè)很有意思的特性:可以從簽名(signature)推導(dǎo)出公鑰(Public Key),以太坊的交易(Transaction)格式只包含了簽名(signature)搀军,驗(yàn)證交易簽名前先用算法推導(dǎo)出公鑰膨俐,然后再進(jìn)行驗(yàn)簽。
/**
* 驗(yàn)證交易簽名罩句。
*/
@Test fun verifyTransactionSignatureTest() {
// 初始化Alice賬戶
val kp1 = generateKeyPair() ?: return
val alice = Account(kp1.public)
// 初始化Bob賬戶
val kp2 = generateKeyPair() ?: return
val bob = Account(kp2.public)
// Alice向Bob轉(zhuǎn)賬100
val trx = Transaction(alice.address, bob.address, 100, DateTime(), kp1.public)
// Alice用私鑰簽名
val signature = trx.sign(kp1.private)
// 用Alice的公鑰驗(yàn)證交易簽名
assert(verifyTransactionSignature(trx, signature))
}
交易簽名和驗(yàn)證功能完成后焚刺,區(qū)塊鏈的節(jié)點(diǎn)就能夠校驗(yàn)交易(Transaction)的合法性,校驗(yàn)通過(guò)的交易數(shù)據(jù)就能夠加入到區(qū)塊(Block)里门烂。本系列的下一篇將會(huì)討論區(qū)塊鏈的區(qū)塊(Block)設(shè)計(jì)和實(shí)現(xiàn)乳愉。