3

I am trying to recreate effect of web3's eth.accounts.sign in PHP and I struggle to find good resources how to do it properly.

I have seen this (found it thanks to this thread) and based on what I figured out, I've put together script, that outputs something but it's definitely invalid signature.

<?php

use kornrunner\Keccak;
use Elliptic\EC;

//used libraries simplito/elliptic-php kornrunner/keccak

require_once "vendor/autoload.php";

$ec = new EC('secp256k1');
$pkey = "cdf6a858b71520aedaf50442a761af94a516a3d0e36f2b5b6c9bcf0bfbe45820";
//$addr = "0x703632A0b52244fAbca04aaE138fA8EcaF72dCBC";

$ecPrivateKey = $ec->keyFromPrivate($pkey, 'hex');

$hash = Keccak::hash('Hello World', 256);

$signature = $ecPrivateKey->sign($hash, ['canonical' => true]);

$r = $signature->r->toString(16);
$s = $signature->s->toString(16);
$v = $signature->recoveryParam + 35;

echo "Signed Hello world is:\n";
echo "Using my script:\n";
echo "0x" . $r . $s . $v . "\n";
echo "Using MEW:\n";
echo "0x2f52dfb196b75398b78c0e6c6aee8dc08d7279f2f88af5588ad7728f1e93dd0a479a710365c91ba649deb6c56e2e16836ffc5857cfd1130f159aebd05377d3a01c\n";

There are some confusing parts of this, I am unsure why 35 is added to recoveryParam and why it's allways 0 from get-go. Also, apparently, chain ID influences V, but this behaviour isn't present in MEW signing. I don't know which order is correct - r s v, or s r v, or v s r, I've seen it used in seemingly random orders (except v is allways last or first), I tried with adding 0x before pkey, and at this point Im out of ideas.

My question is either what am I doing wrong, or where can I learn how to achieve desired effect (without reading tons of JavaScript code that I struggle to understand).

Background: I need this to generate server-side parameter to smart contract (that's signature to other parameters for smart contract) that will be given to user, and smart contract must be able to trust this parameter. Signing it server-side will prevent potentially malicious actor to for example burp proxy the website and mix up said parameters.

1

So method was in the most part correct, but I was wrong in 2 parts. First, v is not +35, but it's +27, and it's supposed to be changed to hexes (hexdec()).

More importantly, ethereum signed message must contain something that resembles "magic bytes" - it's

$message = "\x19Ethereum Signed Message:\n" . strlen($message) . $message;

So working and complete code is:

<?php

use kornrunner\Keccak;
use Elliptic\EC;

require_once "vendor/autoload.php";

$ec = new EC('secp256k1');
$pkey = "0xcdf6a858b71520aedaf50442a761af94a516a3d0e36f2b5b6c9bcf0bfbe45820";
//$addr = "0x703632A0b52244fAbca04aaE138fA8EcaF72dCBC";

$ecPrivateKey = $ec->keyFromPrivate($pkey, 'hex');

$message = "Hello World";

$message = "\x19Ethereum Signed Message:\n" . strlen($message) . $message;

$hash = Keccak::hash($message, 256);

$signature = $ecPrivateKey->sign($hash, ['canonical' => true]);

$r = $signature->r->toString(16);
$s = $signature->s->toString(16);
$v = dechex($signature->recoveryParam + 27);

echo "Signed Hello world is:\n";
echo "Using my script:\n";
echo "0x$r$s$v\n";
echo "Using MEW:\n";
echo "0x2f52dfb196b75398b78c0e6c6aee8dc08d7279f2f88af5588ad7728f1e93dd0a479a710365c91ba649deb6c56e2e16836ffc5857cfd1130f159aebd05377d3a01c\n";

Now It can be validated by simple smart contract.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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