I'm trying this code example : https://thomasclowes.com/verifying-an-ethereum-signature-on-the-server-php-2/

Expected $recoveredSenderAddress = 0xd5bfc359c3a377bb8afd41db8ffc8d1349718233

Actual $recoveredSenderAddress = 0x65f0041f24b95b4d73cb128491b592f08a432c37

Tested transaction is => https://ropsten.etherscan.io/tx/0xc14a23d652315c871474142745bc23268e0fac2ee9f0d56a108e208571c03a86

// $transactionRaw = 'f86a06843b9aca00835d161494e2f9d68bb0d2adcb0d926e93896366d0f2a4573886313030303030801ba0a267b2cd995a8475b967f688d96af1442af777c545cac8d35d08225e31167b32a066308ac688f621ad3f284a63153af7d7c711409926ac0c7e0231fdf0f005b74f';

public function recoveredSenderAddress($transactionRaw)
    $rlp = new RLP; // Lib Web3p\RLP\RLP (Recursive Length Prefix)
    $decodedArray = $rlp->decode('0x'.$transactionRaw);

    $rHex = $decodedArray[7]->toString('hex');
    $sHex = $decodedArray[8]->toString('hex');
    $vValue = $decodedArray[6][0];

    //"v" => 27
    //"r" => "a267b2cd995a8475b967f688d96af1442af777c545cac8d35d08225e31167b32"
    //"s" => "66308ac688f621ad3f284a63153af7d7c711409926ac0c7e0231fdf0f005b74f"

    $messageHex       = $transactionRaw;
    $messageByteArray = unpack('C*', hex2bin($messageHex));
    $messageGmp       = gmp_init("0x" . $messageHex);

    $r = $rHex;     //hex string without 0x
    $s = $sHex;     //hex string without 0x
    $v = $vValue;   //27 or 28

    //with hex2bin it gives the same byte array as the javascript
    $rByteArray = unpack('C*', hex2bin($r));
    $sByteArray = unpack('C*', hex2bin($s));

    $rGmp = gmp_init("0x" . $r);
    $sGmp = gmp_init("0x" . $s);

    $signature = array_merge($rByteArray, $sByteArray);

    $recovery = $v - 27;
    if ($recovery !== 0 && $recovery !== 1) {
        throw new Exception('Invalid signature v value');

    $publicKey = Signature::recoverPublicKey($rGmp, $sGmp, $messageGmp, $recovery);

    $recoveredSenderAddress = "0x".substr(hash('sha3-256',hex2bin($publicKey['x'].$publicKey['y'])), 24);

    return $recoveredSenderAddress;

What am I doing wrong ? Thx !

  • I can send you a snippet to decode a transaction in golang, its 60 lines of code. It takes raw transaction from stdin and dumps all the values to stdout. You can compile it as executable and invoke from your PHP with exec() , or you can compile it as a php extension if you know how to write an extension.
    – Nulik
    Sep 22, 2018 at 11:45
  • 1
    I've to note that ethereum uses keccak256 instead of the oficial sha3, see this question stackoverflow.com/questions/44742153/keccak-256-in-php.
    – Ismael
    Sep 24, 2018 at 15:52
  • @Nulik Thank you but I would like to do it in php. There are implementations that work in JS also like ethereumjs-tx for example but my goal is to understand the problem in this script
    – vincentLg
    Sep 24, 2018 at 22:40
  • @Ismael thank you for your help. After some tests, and comparing step by step with the JS version that works, even before the use of sha3, the $publicKey in my script is not good. Actual 49b3c834a579e4e8d03c4fe3faed5ae6f5cc8766c1de0f5091f51a5885f35356fd1000711dbfc31fb9ec01c0dadca1d9a2b89d3b92f69b63d0c7971410d0a687 Expected 52721ad1fcf8d852853c395e614101a11e29eb3c9e583f147b0d9cde79986b3c451abe7cc8f7aeccc16f168dbd9c48777369f395158c5d02aaea229eca5f649f
    – vincentLg
    Sep 24, 2018 at 22:44
  • @vincentLg Your issue is because you verify the raw transaction, and you have to verify the hash of the transaction without signature (ie without r, s and v). Take a look at github.com/web3p/ethereum-tx/blob/master/src/…. Sorry I'd try to write an example but I'm not very good at php.
    – Ismael
    Oct 13, 2018 at 19:55

1 Answer 1


You may use a library for that https://github.com/digitaldonkey/ecverify

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.