Nodejs

Keccak256() 的不同輸出,哪一個是正確的?

  • August 22, 2019

為了從合約儲存中獲取價值,我成功地使用了這個 geth 程式碼:

var contractAddress = '0x88e726de6cbadc47159c6ccd4f7868ae7a037730'
var index = '0000000000000000000000000000000000000000000000000000000000000001'
var key =  '00000000000000000000000x8703f7b22fc5613497aee971e80480a46b226d3c'
var newKey =  web3.sha3(key + index, {"encoding":"hex"})
   newKey: "0x749bce6b8d0b50e46cbdb3872aefff8c0e7eee46cc4368971ef94ce14e0c3839"

console.log('TokenBalance: ' + web3.toDecimal(web3.eth.getStorageAt(contractAddress, newKey)))
TokenBalance: 1000000000

但是,當嘗試在 GoLang 上實現相同的程式碼時,雜湊 newKey 是不同的,並且一切都失敗了。

Code at https://play.golang.org/p/6z8EX44A3QX

   package main

   import "fmt"
   import "encoding/hex"
   import "github.com/ethereum/go-ethereum/crypto"

   func main() {
       index := "0000000000000000000000000000000000000000000000000000000000000001"
       key := "00000000000000000000000x8703f7b22fc5613497aee971e80480a46b226d3c"

       // Crunching hash index for contract token balance at address 0x8703f7b22fc5613497aee971e80480a46b226d3c
       // var newKey =  sha3(key + index, {"encoding":"hex"})
       var newKey = crypto.Keccak256([]byte(key + index))
       fmt.Println("newKey: ", newKey)
       fmt.Println(hex.Dump(newKey))
       fmt.Println(hex.EncodeToString(newKey))
   }

Output:
   newKey:  [236 52 49 125 144 82 178 166 201 55 151 68 129 249 89 25 207 168 159 24 108 235 39 14 14 14 169 233 76 45 248 192]
   00000000  ec 34 31 7d 90 52 b2 a6  c9 37 97 44 81 f9 59 19  |.41}.R...7.D..Y.|
   00000010  cf a8 9f 18 6c eb 27 0e  0e 0e a9 e9 4c 2d f8 c0  |....l.'.....L-..|
   ec34317d9052b2a6c937974481f95919cfa89f186ceb270e0e0ea9e94c2df8c0

在 nodeJs 上嘗試相同的雜湊時,我得到與 GoLang 相同的結果,但與 geth 節點不同:

$node
   var util = require('ethereumjs-util');
   var web3 = require("web3");

   var index = '0000000000000000000000000000000000000000000000000000000000000001';
   var key =  '00000000000000000000000x8703f7b22fc5613497aee971e80480a46b226d3c';
   var newKey1 =  web3.utils.sha3(key + index, {"encoding":"hex"});
   var newKey2 = util.keccak256(key+index);

   console.log("NEWKEY 1", newKey1);
   console.log("NEWKEY 2", "0x"+newKey2.toString('hex'));

Output:
   NEWKEY 1 0xec34317d9052b2a6c937974481f95919cfa89f186ceb270e0e0ea9e94c2df8c0
   NEWKEY 2 0xec34317d9052b2a6c937974481f95919cfa89f186ceb270e0e0ea9e94c2df8c0

在 go-ethereum 原始碼中,我可以確認 sha3 實現是 keccak256:

node\api.go(313):
   // Sha3 applies the ethereum sha3 implementation on the input.
   // It assumes the input is hex encoded.
   func (s *PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes {
       return crypto.Keccak256(input)
   }

嘗試使用線上工具計算 sha3/keccak256 時,情況變得更糟:

At https://emn178.github.io/online-tools/keccak_256.html        
   input: 000000000000000000000000000000000000000000000000000000000000000100000000000000000000000x8703f7b22fc5613497aee971e80480a46b226d3c
   output: fcc55d8cd146d5891583a2120b6546cc0e95a73b831ce3d165a6bc3bafe777e7

我想我需要對 ASCII 字元串表示進行雜湊處理,因此首先嘗試將字元串轉換為十六進制:

At http://string-functions.com/string-hex.aspx
   string: 000000000000000000000000000000000000000000000000000000000000000100000000000000000000000x8703f7b22fc5613497aee971e80480a46b226d3c
   hex: 3030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303130303030303030303030303030303030303030303030307838373033663762323266633536313334393761656539373165383034383061343662323236643363

和線上雜湊:

At https://emn178.github.io/online-tools/keccak_256.html
   input: 3030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303130303030303030303030303030303030303030303030307838373033663762323266633536313334393761656539373165383034383061343662323236643363
   output: 1bf2aa0bc8831bea8e5cfa462d8a825f0ed66b406b37fb63dd10ae6ebbf87ccc

Or padding with 0x:
   input: 0x3030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303130303030303030303030303030303030303030303030307838373033663762323266633536313334393761656539373165383034383061343662323236643363
   output: 6d09c345f835d959e3bcb83f0e6612d92041f901c041daf5448dbbf04c59af65

所有三個不同的輸出。怎麼可能?感謝任何提示!

順便說一句,我閱讀了這個問題和答案,但沒有找到我的答案: 哪個 sha3 輸出是正確的? keccak256 函式的不同雜湊值?

這基本上取決於將輸入數據解釋為字節或字元串。測試這一點的一個好方法是在瀏覽器中使用 web3(例如,只需訪問 remix 站點,您就可以使用一個控制台視窗。這顯示了以下內容:

> web3.utils.keccak256("0x00000000000000000000000x8703f7b22fc5613497aee971e80480a46b226d3c0000000000000000000000000000000000000000000000000000000000000001")
0x749bce6b8d0b50e46cbdb3872aefff8c0e7eee46cc4368971ef94ce14e0c3839
> web3.utils.keccak256("00000000000000000000000x8703f7b22fc5613497aee971e80480a46b226d3c0000000000000000000000000000000000000000000000000000000000000001")
0xec34317d9052b2a6c937974481f95919cfa89f186ceb270e0e0ea9e94c2df8c0

(第一個是您想要用於訪問合約儲存的案例)

我不是特別了解 Go,但它可能會將字元串的 ASCII 文本轉換為字節,並在後面的範例中提供類似於“0x3030303030 …”字元串的內容,這是您絕對不想要的。

如果您在字元串前面加上“0x”,我希望您的節點範例可以工作,因為它會將其解釋為數字而不是字元串:

var newKey2 = util.keccak256("0x"+key+index);

您的 github 範例的參數方式錯誤!

這是一個使用真實世界數字的簡單測試,您可以嘗試使用各種語言來查看是否可以使其工作:

> web3.utils.keccak256("0x00")
0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a
> web3.utils.keccak256("0x0")
0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a
> web3.utils.keccak256("00")
0xe3f0ae350ee09657933cd8202a4dd563c5af941f8054e6d7191e3246be378290
> web3.utils.keccak256("0")
0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d

您會注意到前兩個返回相同的結果,這意味著輸入被正確解碼為單個(零)字節,而其他兩個被解釋為字元串。

希望這可以幫助!

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