BitcoinPHP / BitcoinECDSA.php

PHP library to generate BTC addresses and signatures from private keys.
223 stars 106 forks source link

Method: checkSignatureForRawMessage() fails when a signed message is provided. #21

Closed tuaris closed 9 years ago

tuaris commented 9 years ago

My issue is best explained by examples.

It works if I do it this way:

$bitcoinECDSA = new BitcoinECDSA();
$bitcoinECDSA->generateRandomPrivateKey();

$signedMessage =  $bitcoinECDSA->signMessage("Test 1234");

echo $signedMessage . PHP_EOL;
$result = $bitcoinECDSA->checkSignatureForRawMessage($signedMessage);
echo 'Message Signature Valid: ' . ($result ? 'True' : 'False') . PHP_EOL;

Result:

-----BEGIN BITCOIN SIGNED MESSAGE-----
Test 1234
-----BEGIN SIGNATURE-----
1QByU6YzFcUwA5QX759cg2eFhkdTCV7CtW
H/B2dpyiirAV3dW1aqAtyu7KQylz47DyS/GSXo2DLEiiyfFArocW7T6TVss6WXhZDyeu6AraLPrJLju+DXRz6I0=
-----END BITCOIN SIGNED MESSAGE-----
Message Signature Valid: True

If I do this:

$bitcoinECDSA = new BitcoinECDSA();

$signedMessage = "-----BEGIN BITCOIN SIGNED MESSAGE-----" . PHP_EOL;
$signedMessage .= "Test 1234" . PHP_EOL;
$signedMessage .= "-----BEGIN SIGNATURE-----" . PHP_EOL;
$signedMessage .= "1QByU6YzFcUwA5QX759cg2eFhkdTCV7CtW" . PHP_EOL;
$signedMessage .= "H/B2dpyiirAV3dW1aqAtyu7KQylz47DyS/GSXo2DLEiiyfFArocW7T6TVss6WXhZDyeu6AraLPrJLju+DXRz6I0=" . PHP_EOL;
$signedMessage .= "-----END BITCOIN SIGNED MESSAGE-----";

echo $signedMessage . PHP_EOL;
$result = $bitcoinECDSA->checkSignatureForRawMessage($signedMessage);
echo 'Message Signature Valid: ' . ($result ? 'True' : 'False') . PHP_EOL;

I get this:

Fatal error:  Uncaught exception 'Exception' with message 'No Private Key was defined'

Okay, so I add to the above:

$bitcoinECDSA->generateRandomPrivateKey();

Fails.

-----BEGIN BITCOIN SIGNED MESSAGE-----
Test 1234
-----BEGIN SIGNATURE-----
1QByU6YzFcUwA5QX759cg2eFhkdTCV7CtW
H/B2dpyiirAV3dW1aqAtyu7KQylz47DyS/GSXo2DLEiiyfFArocW7T6TVss6WXhZDyeu6AraLPrJLju+DXRz6I0=
-----END BITCOIN SIGNED MESSAGE-----
Message Signature Valid: False

What am I doing wrong?

rgex commented 9 years ago

Acknowledged, I'm going to investigate it soon.

tuaris commented 9 years ago

Found the issue on https://github.com/BitcoinPHP/BitcoinECDSA.php/blob/master/src/BitcoinPHP/BitcoinECDSA/BitcoinECDSA.php#L1203

$R = bin2hex(substr($signature, 1, 64));
$S = bin2hex(substr($signature, 65, 64));

Should be:

$R = bin2hex(substr($signature, 1, 32));
$S = bin2hex(substr($signature, 33, 64));
tuaris commented 9 years ago

One last error on https://github.com/BitcoinPHP/BitcoinECDSA.php/blob/master/src/BitcoinPHP/BitcoinECDSA/BitcoinECDSA.php#L558

if(true == $compressed)
{
    return '04' . $pubKey['x'] . $pubKey['y'];
}

Should be:

if(true != $compressed)
{
    return '04' . $pubKey['x'] . $pubKey['y'];
}

After those two corrections, everything appears to be working correctly. Pull request is here: #22