How can i run abi.encodePacked in golang?
in solidity i use keccak256(abi.encodePacked(a, b))
to calc the signature of the params.
here is my contract.
pragma solidity ^0.4.24;
import "openzeppelin-solidity/contracts/ECRecovery.sol";
contract MyContract {
using ECRecovery for bytes32;
address permittedSinger;
function doSomething(
bytes32 id, uint256 amount, bytes sig
) {
bytes32 hash = getHash(msg.sender, id, amount);
address msgSigner = hash.recover(sig);
require(msgSigner == permittedSinger);
}
function getMsgSigner(bytes32 proveHash, bytes sig) public pure returns (address) {
return proveHash.recover(sig);
}
function getHash(
address receiver, bytes32 id, uint256 amount
) pure returns (bytes32) {
return keccak256(abi.encodePacked(receiver, id, amount));
}
}
finally I managed to do it. :)
package main
import (
"math/big"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/accounts/abi"
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/sha3"
)
func main() {
uint256Ty, _ := abi.NewType("uint256")
bytes32Ty, _ := abi.NewType("bytes32")
addressTy, _ := abi.NewType("address")
arguments := abi.Arguments{
{
Type: addressTy,
},
{
Type: bytes32Ty,
},
{
Type: uint256Ty,
},
}
bytes, _ := arguments.Pack(
common.HexToAddress("0x0000000000000000000000000000000000000000"),
[32]byte{'I','D','1'},
big.NewInt(42),
)
var buf []byte
hash := sha3.NewKeccak256()
hash.Write(bytes)
buf = hash.Sum(buf)
log.Println(hexutil.Encode(buf))
// output:
// 0x1f214438d7c061ad56f98540db9a082d372df1ba9a3c96367f0103aa16c2fe9a
}
As Jakub N
is said in comments to accepted answer, Go's arguments.Pack
returns as abi.encode
and not abi.encodePacked
. In your case it works because all packed values are 32 bytes, but if you also add some strings then the result will be different.
Here is how to do it to be compatible with tightly packed encoding corresponding to abi.encodePacked
:
// hash of packed byte array with arguments
hash := crypto.Keccak256Hash(
common.HexToAddress("0x0000000000000000000000000000000000000000").Bytes(),
[32]byte{'I','D','1'},
common.LeftPadBytes(big.NewInt(42).Bytes(), 32),
[]byte("Some other string value"),
)
// normally we sign prefixed hash
// as in solidity with `ECDSA.toEthSignedMessageHash`
prefixedHash := crypto.Keccak256Hash(
[]byte(fmt.Sprintf("\x19Ethereum Signed Message:\n%v", len(hash))),
hash.Bytes(),
)
// sign hash to validate later in Solidity
sig, err := crypto.Sign(prefixedHash.Bytes(), privateKey)
It is also more efficient as we don't pack and allocate additional memory for that. Hash function iterates over existing values.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With