how to get correct address using ecrecover in tron

2.2k Views Asked by At

The code block of getting signer address via ecrecover in solidity contract code is working well with Ethereum but in TRON it is returning wrong address My contract side code is

    function validate(string memory strTest,uint8 v, bytes32 r, bytes32 s) public view returns(address){
      bytes32 prefixedHash = keccak256(strTest);
      return ecrecover(keccak256(prefixedHash),v,r,s);
      // return ecrecover(prefixedHash,v,r,s):
   }

and dapp side code is

    msg = tronWeb.sha3("this is test string");
    var signature = await tronWeb.trx.sign(msg);
    var r=signature.substr(0,66);
    var s= "0x" + signature.substr(66,64);
    var v="0x" + signature.substr(signature.length-2);
    retValue = await thisContractInstance.validate("this is test string",v,r,s).call();

but in both cases ( one case is commented in contract side code) getting wrong signer address in TRON shasta network

4

There are 4 best solutions below

0
On BEST ANSWER

Taken from here:

The smart contract code:

contract Verifier {
    function recoverAddr(bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) returns (address) {
        return ecrecover(msgHash, v, r, s);
    }

    function isSigned(address _addr, bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) returns (bool) {
        return ecrecover(msgHash, v, r, s) == _addr;
    }
}

The client code:

const ethers = tronWeb.utils.ethersUtils;
let contract = await tronWeb.contract().at(contract_address);
let signingKey = new ethers.SigningKey(tronWeb.defaultPrivateKey);

let message = "This is some message";
let messageBytes = ethers.toUtf8Bytes(message);
let messageDigest = ethers.keccak256(messageBytes);

let signature = signingKey.signDigest(messageDigest);
let hexAddress = await contract.recoverAddr(messageDigest, signature.v, signature.r, signature.s).call();
0
On

Are you trying to sign a string or sign transaction? @ashwin

I had the same kind of issues signing a string, and the below helped me out. Tronweb uses different methods for signing transactions and signing strings.

1) For transactions you can refer this: https://github.com/TRON-US/tronweb/blob/master/src/lib/trx.js#L651,

2) Regarding signing string, it uses

ethers.utils.SigningKey.signDigest ()

of Ethereum: https://docs.ethers.io/ethers.js/html/api-advanced.html?highlight=signingkey#id8, note that the final v byte will always be nomalized for Solidity (either 27 or 28)

If you are trying to sign the msg as mentioned here,

var signature = await tronWeb.trx.sign(msg);

you can follow the second.

0
On

You could refer the article https://medium.com/@coredevs/verifying-elliptic-curve-digital-signature-with-tron-smart-contract-5d11347e7b5b. This will be useful to accomplish signing the strings, along with the above answer provided by @Aldo. Happy coding.

0
On

According to https://github.com/tronprotocol/tronweb/blob/1435436f83b910f19e9205998e348ea093732ce5/src/lib/trx.js#L629

tronWeb.trx.sign() does the following

  1. Pass in 32 bytes of hash
  2. The prefix "\x19TRON Signed Message:\n32" needs to be added first
  3. Generate a new hash with the keccak256 algorithm
  4. Signature (TronLink or private key)

Therefore, when using solidity's ecrecover, the hash of step 3 is passed in.

function getHash(hash) {

    hash = hash.replace(/^0x/, '')

    if (!tronWeb.utils.isHex(hash)) {
        return
    }

    if (hash.length !== 64) {
        return
    }

    const {
        keccak256,
        toUtf8Bytes
    } = tronWeb.utils.ethersUtils

    const hashArray = tronWeb.utils.code.hexStr2byteArray(hash)

    const TRX_MESSAGE_PREFIX = toUtf8Bytes('\x19TRON Signed Message:\n32')

    return keccak256([
        ...TRX_MESSAGE_PREFIX,
        ...hashArray
    ])
}