Contract-Deployment

ethers.js 通過 v,r,s 值從合約部署中恢復公鑰

  • January 12, 2020

我目前正在嘗試獲取部署契約的使用者的公鑰。不幸的是我不能讓它工作。

我試圖僅通過使用 ethers.js 來實現這一點,因為我不想讓我的 React 建構與其他包一起膨脹。我可以使用取自此問題的以下程式碼輕鬆地從給定簽名中獲取公鑰。

   let msg = "This is a normal string.";
   let sig = await signer.signMessage(msg);
   const msgHash = ethers.utils.hashMessage(msg);
   const msgHashBytes = ethers.utils.arrayify(msgHash);
   const recoveredPubKey = ethers.utils.recoverPublicKey(msgHashBytes, sig);
   const recoveredAddress = ethers.utils.recoverAddress(msgHashBytes, sig);

在部署合約時,我應該能夠通過簡單地將r,sv取自deployTransaction. 文件中的範例類似。這是我的程式碼:

   const deployTx = contract.deployTransaction;
   const msgHash = ethers.utils.hashMessage(deployTx.raw);
   const dataBytes = ethers.utils.arrayify(msgHash);
   const expanded = {
     r: deployTx.r,
     s: deployTx.s,
     recoveryParam: 0,
     v: deployTx.v
   };
   const signature = ethers.utils.joinSignature(expanded);

   // now the signature should be correctly formatted
   const recoveredPubKey = ethers.utils.recoverPublicKey(dataBytes, signature);
   const recoveredAddress = ethers.utils.recoverAddress(dataBytes, signature);

這種方法行不通。據我所知,部署期間簽署的數據位於deployTransaction.raw. 所以這應該有效。但我也對其進行了測試deployTransaction.data

在我看來,簽名可能是錯誤的。joinSignature自動將值轉換v為 27 或 28。根據EIP155,這沒有任何意義嗎?

**編輯:**澄清一下,我認為我需要的只是真正的簽名雜湊。我怎樣才能生成它?這顯然不是原始部署事務的雜湊。

**編輯 2:**在對乙太坊書籍進行一些研究後,我發現了這一點:

In Ethereum’s implementation of ECDSA, the "message" being signed is the transaction, or more accurately, the Keccak-256 hash of the RLP-encoded data from the transaction. The signing key is the EOA’s private key.

因此,我將程式碼更改為以下內容:

   const deployTx = contract.deployTransaction;
   const msg = ethers.utils.RLP.encode(deployTx.data);
   const msgHash = ethers.utils.keccak256(msg);
   const msgBytes = ethers.utils.arrayify(msgHash);
   const expanded = {
     r: deployTx.r,
     s: deployTx.s,
     recoveryParam: 0,
     v: deployTx.v
   };
   const signature = ethers.utils.joinSignature(expanded);
   const recoveredPubKey = ethers.utils.recoverPublicKey(
     msgBytes,
     signature
   );
   const recoveredAddress = ethers.utils.recoverAddress(msgBytes, signature);

不幸的是,這仍然不起作用。

現在解決了。程式碼和庫中存在一個小錯誤,ethers無法正確返回 chainId 併計算v值。現在已經修好了,看這裡。非常感謝 ricmoo 的幫助。

我寫了一個要點,可以正確恢復給定交易的公鑰

簡而言之:

const tx = await provider.getTransaction(...)
const expandedSig = {
 r: tx.r,
 s: tx.s,
 v: tx.v
}
const signature = ethers.utils.joinSignature(expandedSig)
const txData = {
 gasPrice: tx.gasPrice,
 gasLimit: tx.gasLimit,
 value: tx.value,
 nonce: tx.nonce,
 data: tx.data,
 chainId: tx.chainId,
 to: tx.to // you might need to include this if it's a regular tx and not simply a contract deployment
}
const rsTx = await ethers.utils.resolveProperties(txData)
const raw = ethers.utils.serializeTransaction(rsTx) // returns RLP encoded tx
const msgHash = ethers.utils.keccak256(raw) // as specified by ECDSA
const msgBytes = ethers.utils.arrayify(msgHash) // create binary hash
const recoveredPubKey = ethers.utils.recoverPublicKey(msgBytes, signature)
const recoveredAddress = ethers.utils.recoverAddress(msgBytes, signature)

引用自:https://ethereum.stackexchange.com/questions/78815