1

I have to implement a login system with a web3modal using WalletConnect & MetaMask.

After many attempts, it seems that all the existing source codes about this on the internet only work with MetaMask and some walletConnect provider which is problematic.

The following algorithm is stopping during the check of ($recid != ($recid & 1)) which return false while trying to connect with another Provider than MetaMask. Why the $recid would be incorrect?

  function pubKeyToAddress($pubkey) 
  {
    return "0x" . substr(Keccak::hash(substr(hex2bin($pubkey->encode("hex")), 1), 256), 24);
  }

  function verifySignature($message, $signature, $address) 
  {
    $msglen = strlen($message);
    $hash   = Keccak::hash("\x19Ethereum Signed Message:\n{$msglen}{$message}", 256);

    $sign   = ["r" => substr($signature, 2, 64),
               "s" => substr($signature, 66, 64)];
    $recid  = ord(hex2bin(substr($signature, 130, 2))) - 27;

    if ($recid != ($recid & 1))
        return false;

    $ec = new EC('secp256k1');
    $pubkey = $ec->recoverPubKey($hash, $sign, $recid);

    return $address == pubKeyToAddress($pubkey);
  }

I thought at first that the code would come from JS so I managed to change the part where I send the data in Ajax, but it still doesn't work... This is the code to communicate with the server:

 function handleSignMessage(rawMessage, publicAddress) {
       let message = web3ModalProv.utils.utf8ToHex(rawMessage);

       return new Promise((resolve, reject) =>  
       web3ModalProv.eth.personal.sign(
         message,
         publicAddress, // the publicAddress is already lowered
           (err, signature) => {
             if (err || typeof signature === 'undefined') {
               userLoginData.state = "loggedOut";
               showMsg(userLoginData.state);
             }

             return resolve({ publicAddress, signature });
           }
         )
       )
     }

I already tried many sources to make the algorithm. You can find below every source about this, and the git of Keccak & EC packages

2
  • What's recid value? Are you signing with mainnet or some other blockchain? What's that networkId?
    – Ismael
    Oct 28, 2022 at 22:44
  • eth mainnet, using Zerion wallet. The issue came from PHP algorithm to recover public key, most likely the Keccak PHP library
    – Gniax
    Oct 29, 2022 at 23:06

1 Answer 1

1

I managed to fix the issue which was actually on the back-end (verifySignature). The issue probably comes from the Keccak library as it was blocked at if ($recid != ($recid & 1)) return false;

Solution:

Include php-ecrecover in your project

This needs the following version of CryptoCurrencyPHP (I did not tested the HEAD one)

Simply replace function verifySignature() by:

function verifySignature($message, $signature, $address) 
{
    return $address == personal_ecRecover($message, $signature);
}

The personal_ecRecover function is based on gmp and looks more efficient than the current public key recovery method which seems to have been developed only for MetaMask.

You might need to allow gmp extension in php.ini if not done

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.