Это не вопрос о проблеме с Ethereum, использующим нестандартный sha3 . Я нашел правильную библиотеку хеширования JS и могу получить совпадающие хэши в JS и Solidity для байтовых строк. Мне интересно, как представить uint при передаче его в хеш-библиотеку JS, чтобы он приводил к тому же хешу, что и созданный Solidity sha3.
JS
'0x' + keccak(
1
)
// 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
Solidity
sha3(
1
);
// 0x5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2
Ответ Жеана великолепен, но нам нужно объяснить еще одну вещь: почему sha3(1)
в твердости создается b10e2d...fa0cf6
?
Это связано с тем, что функция sha3 Solidity хэширует свои входные данные на основе типов аргументов . Таким образом, значение 1
будет генерировать другой хэш, если оно хранится как bytes8
, bytes16
, bytes32
и т. д. Поскольку sha3(1)
передается 1
как числовой литерал, оно преобразуется в наименьший необходимый тип, uint8
1 .
8 бит умещаются в 2 шестнадцатеричных символа, поэтому, если вы дополните свой ввод двумя символами, вы получите тот же результат в web3:
Javascript:
web3.sha3(leftPad((1).toString(16), 2, 0), { encoding: 'hex' })
// 5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2
Точно так же вы можете указать число на стороне твердости:
Прочность:
// uint is equivalent to uint256
sha3(uint(1))
// b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6
Javascript:
// note that the value is padded by 64 characters to fit 256 bits
web3.sha3(leftPad((1).toString(16), 64, 0), { encoding: 'hex' })
// b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6
BigNumber
типах:Они не работают автоматически с web3.sha3
. Сначала вы должны преобразовать их в шестнадцатеричный формат.
Прочность:
sha3(uint(100 ether))
// c7cc234d21c9cfbd4632749fd77669e7ae72f5241ce5895e410c45185a469273
Javascript:
// the .slice is to remove the leading '0x'
web3.sha3(leftPad(web3.toHex(web3.toWei(100)).slice(2).toString(16), 64, 0), { encoding: 'hex' })
// c7cc234d21c9cfbd4632749fd77669e7ae72f5241ce5895e410c45185a469273
Я написал небольшую библиотеку, которая предоставляет версию web3.sha3
, точно соответствующую поведению sha3
в Solidity. Надеюсь, это прояснит все ваши проблемы с хэшированием :). https://github.com/raineorshine/solidity-sha3
Solidity использует шестнадцатеричные значения для внутреннего использования.
> web3.sha3(web3.toHex(1))
"5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2"
Функция Solidity sha3 хэширует байтовое представление uint. То есть число в шестнадцатеричном формате (с основанием 16), дополненное до 32 байт. 32 пустых байта в шестнадцатеричном представлении — это 64 нуля.
Чтобы сделать это в JS, мы можем использовать печально известный пакет left-pad:
const jsHashWeb3 = web3.sha3(leftPad((1).toString(16), 64, 0), { encoding: 'hex' })
// b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6
sha3(1)
производит 0x5fe7f9...dcffd2
не так, b10e2d...fa0cf6
как производит ваш код. Могли бы вы объяснить?
эт
keccak256
дает идентичные результаты,sha3
поэтому все в этой теме относится к файламkeccak256
.