Open arnabghose997 opened 1 year ago
Actually, it's PR'd by the EVMOS team and managed by them, so I don't know.
But I think it's compatible with ethereum. And when you use signEthereum, it looks like ADR-036, it's just because they recycled the ADR-036 page. It doesn't actually change the sign data to ADR-036. As far as I know, in ethereum, the signing data is hashed with keccak256. And if you're successful in getting the public key, that public key should be in uncompressed format, and you should drop the prefix byte, hash it with keccak256, use the last 20 bytes, encode it with bech32, and you should get the corresponding bech32 address.
Can you confirm if it doesn't work?
Thank you @Thunnini for the response. I will let you know here. I have just one question.
When you say that signData is hashed using keccak256, do you mean it is hashed in the following way? :
keccak256("\x19Ethereum Signed Message:\n"${len(signData)}${signData}).
Or, is it something like following, where the hashing of singData happens without any padding like above:
keccak256(signData).
I think it will be keccak256("\x19Ethereum Signed Message:\n"${len(signData)}${signData})
if EthSignType.MESSAGE is used.
Referring to the code, this is the intended behavior for the code.
@Thunnini I tried the approach you suggested, but I wasn't able to recover the correct bech32 address. Following is the code for both client and server for the reference.
client.js
:
const msgToSign = "hi";
const keplrAddress = "osmo1f6r0x3pljpl7pe76zzv36l0ksztqmdltakhv4r";
const keplrChainId = "osmosis-1"
const ethType = "message";
const signatureBytes = await window.keplr.requestMethod("signEthereum", [
keplrChainId,
keplrAddress,
msgToSign,
ethType,
]);
const signatureB64 = Buffer.from(signatureBytes).toString("base64");
console.log("Singature: ", signatureB64); // Will copy it to be used in server.go
server.go
:
import (
"fmt"
"encoding/base64"
etheraccounts "github.com/ethereum/go-ethereum/accounts"
ethercrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/cosmos/btcutil/bech32"
"golang.org/x/crypto/sha3"
)
func main() {
// Hash the message
msg := "hi"
msgHash, _ := etheraccounts.TextAndHash([]byte(msg))
// Decode base54-encoded signature string to bytes
signature := "bSxtpN1hzN4rsafwcmD7DsLMfTVpQpvMz1CmK1s2uDkplsZXnUrmi092yn35/edVKCU/nxZ7VDBB/irjyFBDPBs=" // copied from client.js
signatureBytes, err := base64.StdEncoding.DecodeString(signature)
if err != nil {
return err
}
// Handle the signature recieved from web3-js client package by subtracting 27 from the recovery byte
if signatureBytes[ethercrypto.RecoveryIDOffset] == 27 || signatureBytes[ethercrypto.RecoveryIDOffset] == 28 {
signatureBytes[ethercrypto.RecoveryIDOffset] -= 27
}
// Recover public key from signature
recoveredPublicKey, err := ethercrypto.SigToPub(msgHash, signatureBytes)
if err != nil {
return err
}
uncompressedPublicKeyBytes := ethercrypto.FromECDSAPub(recoveredPublicKey)
// Bech-32 address extraction
// remove prefix byte
sanitisedPublicKey := uncompressedPublicKeyBytes[1:]
// Hash with Kekkac256
addressKekkackHash := kekkackHash(sanitisedPublicKey)
// Use last 20 bytes
addressHash := addressKekkackHash[len(addressKekkackHash)-20:]
// Encode to Bech32
addr, err := hexToBech32("osmo", addressHash)
if err != nil {
panic(err)
}
fmt.Println("Address in Bech 32: %v", addr)
}
func hexToBech32(hrp string, addressBytes []byte) (string, error) {
converted, err := bech32.ConvertBits(addressBytes, 8, 5, true)
if err != nil {
return "", fmt.Errorf("encoding bech32 failed: %w", err)
}
return bech32.Encode(hrp, converted)
}
func kekkackHash(data []byte) []byte {
hasher := sha3.NewLegacyKeccak256()
hasher.Write(data)
return hasher.Sum(nil)
}
I am working on an App which signs a particular message using the
signEthereum()
method https://github.com/chainapsis/keplr-wallet/blob/9ce18e3737b3765c6136b8bf0413c5528e644a78/packages/provider/src/core.ts#L223 and the signature is sent to a Tendermint-based blockchain for verification through RPCOn the blockchain end, we are using the
go-ethereum
library to extract the public key from the signature sent from the App. We have used Kekkac256 as well as Sha256 to hash the signData. However, the extracted address (from the extracted public key) doesn't seem to match the expected bech32 address.The question I have is, whether
signEthereum
encapsulates the message in ADR-036 SignDOC (https://docs.cosmos.network/v0.47/architecture/adr-036-arbitrary-signature) before signing it, or does it handles the message similar topersonal_sign
spec (https://docs.metamask.io/guide/signing-data.html#personal-sign) as utilised by Metamask?