作者:林冠宏 / 指尖下的幽靈
GitHub : https://github.com/af913337456/
騰訊雲專欄: https://cloud.tencent.com/developer/user/1148436/activities
目錄
- 前序
- 數據簽名
- 整體流程
- 非對稱加密
- RLP 序列化
- 數據驗證
- 數據篡改
前序
最近的工作一直是基於 以太坊公鏈 做 DApp 開發,雖然對其各 API 的調用都已經很了解了,但是源碼部分一直還沒深入去看過。工欲善其事,必先利其器,故計划閱讀完 以太坊go 版源碼,后續會更新系列文章。本文主要簡談 sendRawTransaction 是如何保證我們交易安全的。
1.數據簽名
方法:sendRawTransaction
整體流程:
- 傳入各參數 ---->
- 使用
from對應的privateKey與secp256k1算法對各入參簽名得出三個量:V,R,S---->
RLP(遞歸長度前綴) 方式序列比簽名的數據 與 原入參數據 ---->
- 發送到 ETH 節點
sendRawTransaction 函數的各個入參:
- from 發送者錢包地址
- value 數值,為與 decimal 的乘積
- gas 油費,非最終真實使用值,真實為 gasUsed
- gasPrice 油費單價
- data 附屬的數據,可做智能合約函數入參
- nonce 交易系列號,類似id
它們都將會被 from 所對應的密鑰 進行簽名而得出三個量:V,R,S。同時,各個入參依然以原來的可見的形式進入序列化步驟。
注意:
還有另外一個叫做 sendTransaction 的方法,通過分析源碼,可以發現 sendTransaction 內部其實會幫助我們根據我們傳參的 from 字段到節點的 accountManager 賬號管理器中獲取from 的密鑰,來幫我們進行數據簽名,所以,sendTransaction 一般不會用於遠程調用,而用於本地調用,因為只有在本地啟動節點的時候,才能配置我們解鎖的錢包。
所用的簽名加密方式是:非對稱加密 中的 secp256k1 橢圓曲線算法
非對稱加密:
它是一類加密方式的統稱。具體到某種能實現它的算法有下面幾種:
- RSA
- secp256k1 (橢圓曲線)
- ElGamal
- ...
而 sendRawTransaction 用到的就是 secp256k1
RLP 序列化
RLP (遞歸長度前綴)提供了一種適用於任意二進制數據數組的編碼,RLP已經成為以太坊中對對象進行序列化的主要編碼方式。RLP的唯一目標就是解決結構體的編碼問題;對原子數據類型(比如,字符串,整數型,浮點型)的編碼則交給更高層的協議;以太坊中要求數字必須是一個大端字節序的、沒有零占位的存儲的格式。
簽名后,數據將會被發送到 ETH 節點。
2. 數據驗證
對應到以太坊的 sendRawTransaction RPC 接口。
- 收到 RLP 序列化的數據后,先進行 RLP 的反序列化
func (s *PublicTransactionPoolAPI) SendRawTransaction(..., encodedTx hexutil.Bytes) (common.Hash, error) {
tx := new(types.Transaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil { // 反序列化
return common.Hash{}, err
}
return submitTransaction(ctx, s.b, tx)
}
- 數據的基礎校驗,主要是一些范圍限制以及格式限制校驗
- tx.Size() > 32*102
- tx.Value().Sign() < 0
- pool.currentMaxGas < tx.Gas()
- ...
檢查簽名,所使用的是secp256k1.RecoverPubkey方法,secp256k1 本身支持根據簽名信息反推公鑰
用消息和簽名推導出對方的公鑰。再通過公鑰,簽名,消息的哈希值計算出一個叫
r的值,這個r是簽名的一部分,校驗簽名就是拿計算出來的r和簽名中攜帶的r經行對比,如果一致就校驗通過
if C.secp256k1_ext_ecdsa_recover(
context,
(*C.uchar)(unsafe.Pointer(&pubkey[0])),
sigdata, // 簽名
msgdata) == 0 { // msgdata tx 的 hash 內容
return nil, ErrRecoverFailed
}
3. 數據篡改
因為簽名生成的 V R S 是由私鑰進行簽名的,如果修改者只修改了外部的值,例如 value,本來是要轉 10 個 ETH , 被改成轉 100 個,等數據傳到以太坊的時候,在檢查簽名的時候,就會發現不匹配,而拋出錯誤。
