iT邦幫忙

2022 iThome 鐵人賽

DAY 18
0
Web 3

Smart Contract Development Breakdown系列 第 18

Day 18 - Signature, Sign, Sign Message & Transaction

  • 分享至 

  • xImage
  •  

Signature, Sign, Sign Message & Transaction

Synchronization Link Tree


Background

本章的主題會把接續昨天的數位簽章把整個 Sign 的原理及應用梳理完畢,首先要知道的一個情況是我們常常會使用「私鑰來對一個信息進行簽章」。而這邊有幾件事情非常重要:

  1. 持有私鑰的人或應用程式才能對訊息簽章
  2. 簽章(sign)不等於加密(encrypt),編碼(encode)不等於加密
  3. 互動場景為:SignMsg -> Provider -> Blockchain Node -> Blockchain

在這邊 Provider 可以當作一個幫助客戶端與區塊鏈節點互動的角色,通常會是節點商 Infura、Alchemy 等等。然而我們沒辦法提供私鑰給節點商(Hosting Parity, openning RESTful API)讓他們代替我們簽章(因為他們是中心化的服務),這時候就需要「錢包」,也就是「私鑰管理器」!

於是乎互動過程就變成:Metamask <-> Infura <-> Blockchain Node <-> Blockchain,在 Metamask(當然也可以用其他錢包)背後其實仍然是跟 Infura 互動,只是 Metamask 會在本地端保管好(理想中)我們的私鑰與進行簽章的動作。

Scenes behind transaction

Ethereum Transactions and Signatures, Private/Public-Keys

如果我們今天使用 web3.eth.sendTransaction 的交易物件長這樣:

{
    from:...
    to:...
    value:...
    gas, gasprice, nonce
}

我們需要先把「帳戶解鎖(unlocked account)」後去「簽核交易(web3.eth.signTransaction)」:

> {
    ...
    tx:{
        v:...
        r:..
        s:...
    }
}

在這個步驟中,有兩個元素:

  1. Private Key(32-bytes, 64 hex characters) 經過 ECDSA(Elliptic Curve Digital Signature Algorithm) 變成 Public Key(64 Bytes Long),再變成 Ethereum Account(Keccak Hash of the last 20 bytes of the public key B_96-255(kec(pub_k)))
  2. 建置 Transaction 物件

如果把兩個元素融合就可以變成 Signed Transaction,在 Signed Transaction 中如果擁有 r 和 s,就可以使用 ECRECOVER 來產出 public key 和 ethereum account,這樣就可以確保此交易是合法經過授權的。

Transaction in Ethereum

  1. Constructing Transaction Object
  2. Unlocking Account: Get the Private Key
  3. Use Private Key to Sign Tx Object -> Signed Transaction
  4. 透過 Provider 將交易送到 Node 中的 memPool
  5. 礦工們發現有新的交易進來,會選擇最高手續費的組合並且驗證交易合法性
  6. 礦工在 Local 建立區塊,運作這筆交易的程式碼 & 修改(本機)區塊鏈狀態
  7. 進行 PoW 爭取把這個區塊 Push 上區塊鏈的機會
  8. PoW 成功,廣播這個區塊給其他節點
  9. 其他節點聆聽到這個區塊後進行確認,若是合法則礦工獲得挖礦獎勵

EIP Time

EIP-712: Ethereum typed structured data hashing and signing

現在 Ethereum 的私鑰管理器基本上是使用 EIP-712 來去簽核 msg,而在這之前使用者很難去驗證自己到底簽了什麼,因為在跳出 Metamask 時的是 hexadecimal string,而不是現在看見的可讀字串。在 EIP-712 之後用戶們看見的簽核界面或出現 pre-hash 資訊,也就是 raw data,用戶就可以知道自己到底簽了什麼。

一個簽章機制包含了兩個演算法:一是 hashing algor. 一個是 signing algor.。 Signing algorithm 在 Ethereum 中是 secp256k1,Hashing algorithm 則是 keccak256

在以太坊中有兩種訊息:一個是 transaction 一個是 bytestrings。簽章方式的 RPC Call 分別為 eth_sendTransactioneth_sign

  • 對 Transaction 簽章為 encode(transaction : ?) = RLP_encode(transaction)
    • 其實就是我們之前提到過的 RLP,經過 RLP 之後得到 Signing Data,再經過 hash 得到 Signing Hashing。
  • 對 bytestings(?⁸ⁿ) 簽章則為 encode(message : ?⁸ⁿ) = "\x19Ethereum Signed Message:\n" ‖ len(message) ‖ message

EIP-1271

在合約接收到一個簽章後的訊息時,可以對其進行 recover 來看我們合約中儲存的 Signer 地址與簽章者是否相同,就可以達到檢驗鏈下資訊的用途(需要具備一定安全性),也就是說我們可以在鏈下以私鑰對某個訊息進行簽核,交付到鏈上時可以使用 ecrecover 來辨別簽核這個訊息的私鑰是否與我們認可的 signer 相符。

EIP-1271 幫助我們可以在合約裡面回復簽章來驗證交易者,其實我們也可以使用 OpenZeppelin 中的 ECDSA,辨別簽章中的資訊是否與我們定義的 signer 相符。

pragma solidity ^0.8.13;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

contract Claim is Ownable{
    using ECDSA for bytes32;
    address private signer;

    function setSigner(address signer_) external onlyOwner{
        signer = signer_;
    }

    function recover(bytes32 hash,, bytes memory sig) public {
        address recovered = keccak256(
            abi.encodePacked("\x19Ethereum Signed Message:\n32",
            hash
        )).recover(sig);
        require(signer == recovered, "Signer is invalid!");
    }
} 

Closing

Reference

Sign Messages

交易驗證 ecrecover


最後歡迎大家拍打餵食大學生0x2b83c71A59b926137D3E1f37EF20394d0495d72d


上一篇
Day 17 - Cryptography
下一篇
Day 19 - Nonce(內有空投活動)
系列文
Smart Contract Development Breakdown30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言