iexbase/tron-api-python

Unable to verify TronLink/TronWeb.js signed message in tron-api

mdn522 opened this issue · 10 comments

Javascript Code for Signing Message:

const original_message = "557e3517549cf8ed47d8b205654ea2a7"
const signedtxn = await tronWeb.trx.sign(original_message);
// result 0x862e16c28684bed7162e9a1dd34962882d887610de6c775054ffbad989baec65707b2ba898366c02e9f20730bc2daf54bb7e6d33d77c64f8930f8c9365f5993a1b

Python Code for Verifying Signed Message

from tronapi import Tron
from hexbytes import HexBytes

tron = Tron()

class signed_message:
     # signedtxn variable in javascript
    signature = HexBytes('0x862e16c28684bed7162e9a1dd34962882d887610de6c775054ffbad989baec65707b2ba898366c02e9f20730bc2daf54bb7e6d33d77c64f8930f8c9365f5993a1b')

original_message = "557e3517549cf8ed47d8b205654ea2a7"
address = "<!-- Tron Base58 Address in TronLink/TronWeb -->"
tron.trx.verify_message(original_message, signed_message, address=address)

I am getting this error
ValueError: Signature does not match

plugin hasn't been updated for a long time, let's check

Currently, this code does solve the issue for verifying TronWeb generated signature

from eth_hash.auto import keccak as keccak_256
# message length is 32 chars and message is a hex string without 0x prefix
# eg message = "557e3517549cf8ed47d8b205654ea2a7"
message_hash = keccak_256(header.encode('utf-8') + bytes.fromhex(message))

thanks, let's check this signature feature

message = tron.trx.sign(tron.toHex(text="test"))

print(
    tron.trx.verify_message(tron.toHex(text="test"), message)
)

How to convert tronweb.trx.sign(hexMessage) to UTF format in tronlink wallet

Here is the document code:
https://cn.developers.tron.network/reference/verifymessage
`
// sign a string message

var str = "helloworld";
// convert to hex format and remove the beginning "0x"
var hexStrWithout0x = tronWeb.toHex(str).replace(/^0x/, '');
// conert hex string to byte array
var byteArray = tronWeb.utils.code.hexStr2byteArray(hexStrWithout0x)
// keccak256 computing, then remove "0x"
var strHash= tronWeb.sha3(byteArray).replace(/^0x/, '');
// sign
var signedStr = await tronWeb.trx.sign(strHash);
var tail = signedStr.substring(128, 130);
if(tail == '01')
{
signedStr = signedStr.substring(0,128)+'1c';
}
else if(tail == '00')
{
signedStr = signedStr.substring(0,128)+'1b';
}

// verify the signature
var res = await tronWeb.trx.verifyMessage(strHash,signedStr,'TPNcZ1j55FrGpsaw6K6rVjuL4HfT8ZbBf7')
console.log(res);
true
`

so ,
JS verifyMsg :
txid = tron.toHex(text="test").replace(/^0x/,'')
signedMsg = tron.trx.sign(tron.toHex(text="test"))

Java verifyMsg:
You can find class: SignatureValidator

it is same as tron.trx.sign

Do I understand correctly, this library is not suitable for me to verify the signature if the signature is done on the frontend via tronweb?

@mdn522

Currently, this code does solve the issue for verifying TronWeb generated signature

where does header.encode('utf-8') come from?

For those who will come here. TronLink expects a fixed message length of 32.

To comply with compatibility, you can use something like this:

from tronapi.common.account import Account, Address
from tronapi.trx import TRX_MESSAGE_HEADER
from trx_utils import to_text, to_hex
from tronapi import Tron

TronClient = Tron()
message_hash = TronClient.keccak(text=TRX_MESSAGE_HEADER + '32' + to_text(hexstr=body.nonce))
recovered = Account.recover_hash(to_hex(message_hash), body.sign)
print(address == Address.from_hex('41' + recovered[2:]).decode())

@mdn522

Currently, this code does solve the issue for verifying TronWeb generated signature

where does header.encode('utf-8') come from?

Unfortunately, The HDD where this testing code was stored has failed. But I guess it should be Tron or Ethereum header