Bitcoin EC Recover


In general, ECDSA signatures consist of 3 parameters, r, s and v, that you can use to verify which address (its private key) was used to sign the message. This page aims to recover public key from given r, s, v and hashed message.

Recover Public Key By V/R/S

<?php 

use BitWasp\Buffertools\Buffer;
use BitWasp\Bitcoin\Bitcoin;
use BitWasp\Bitcoin\Key\Factory\PrivateKeyFactory;
use BitWasp\Bitcoin\Signature\TransactionSignature;
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Signature\CompactSignature;


include_once "../libraries/vendor/autoload.php";
include_once("html_iframe_header.php");

$errmsg = '';

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    try {
		
		$ecAdapter = Bitcoin::getEcAdapter();
		$r = Buffer::hex($_POST["R"],32);
		$R = $r->getGmp();
		
		$s = Buffer::hex($_POST["S"],32);
		$S = $s->getGmp();
		
		$recoveryFlag = (int)$_POST["V"];
		$recoveryId = $recoveryFlag - 27 - ($_POST['compression']=="y" ? 4 : 0);
		
		$cs = new CompactSignature($ecAdapter, $R, $S, $recoveryId, $_POST['compression']=="y");
		
		$publicKey = $ecAdapter->recover(Buffer::hex($_POST["msg"]), $cs);
		
		?>
		<div class="alert alert-success">
			<b>Recovered Public Key</b>: <?php echo $publicKey->getHex();?>
		</div>
		<?php
    } catch (Exception $e) {
        $errmsg .= "Problem found. " . $e->getMessage();
    }
} 

if ($errmsg) {
?>
    <div class="alert alert-danger">
        <strong>Error!</strong> <?php echo $errmsg?>
    </div>
<?php
}
?>
<form action='' method='post'>
	
	<div class="form-group">
        <label for="msg">Hash Message (Hex):</label>
        <input class="form-control" type='text' name='msg' id='msg' value='<?php echo $_POST['msg']?>'>
    </div>
	
	<div class="form-group">
        <label for="V">V (Int):</label>
        <input class="form-control" type='text' name='V' id='V' value='<?php echo $_POST['V']?>'>
    </div>
	
    <div class="form-group">
        <label for="R">R (Hex):</label>
        <input class="form-control" type='text' name='R' id='R' value='<?php echo $_POST['R']?>'>
    </div>
	<div class="form-group">
        <label for="S">S (Hex):</label>
        <input class="form-control" type='text' name='S' id='S' value='<?php echo $_POST['S']?>'>
    </div>
	
	<div class="form-group">
        <label for="compression">Public Key:</label>
        <select name="compression" class="form-control" id='compression'>
            <?php
            $yesno = array("y"=>"Has Compression", "n"=>"Without Compression");
            foreach($yesno as $yesno_k=>$yesno_v) {
                echo "<option value='{$yesno_k}'".($yesno_k == $_POST['compression'] ? " selected": "").">{$yesno_v}</option>";
            }
            ?>
        </select>
    </div>
   
    <input type='submit' class="btn btn-success btn-block"/>
</form>
<?php
include_once("html_iframe_footer.php");		

Recover Public Key By DER Signature

<?php 

use BitWasp\Buffertools\Buffer;
use BitWasp\Bitcoin\Bitcoin;
use BitWasp\Bitcoin\Key\Factory\PrivateKeyFactory;
use BitWasp\Bitcoin\Signature\TransactionSignature;
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Signature\CompactSignature;
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Signature\Signature;

include_once "../libraries/vendor/autoload.php";
include_once("html_iframe_header.php");

$errmsg = '';
ini_set("display_errors", "1");
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    try {
		$ecAdapter = Bitcoin::getEcAdapter();
		
		$derSign = Buffer::hex($_POST["der"]);
		if (!TransactionSignature::isDERSignature($derSign)) {
			throw new Exception("DER signature not valid.");
		}
		
		$binary = $derSign->getBinary();
        $nLenR = ord($binary[3]);
		
		$R = $derSign->slice(4, $nLenR)->getGmp();
		$r = ltrim(Buffer::int(gmp_strval($R,10), (int)$nLenR)->getHex(), "00");
		
        $nLenS = ord($binary[5 + $nLenR]);
        $S = $derSign->slice(6 + $nLenR, $nLenS)->getGmp();
		$s = Buffer::int(gmp_strval($S,10), (int)$nLenS)->getHex();
		
		$sigHash = $derSign->slice(6 + $nLenR + $nLenS, 1);
		
		$publicKeys = [];
		foreach(range(0,3) as $V) {
			try {
				$flag = (int)$V + 27 + ($_POST['compression']=="y" ? 4 : 0);
				
				$cs = new CompactSignature($ecAdapter, $R, $S, (int)$V, $_POST['compression']=="y");
				$publicKey = $ecAdapter->recover(Buffer::hex($_POST["msg"]), $cs);
				
				$publicKeys[] = $publicKey->getHex() . " (RecoveryId = {$V})";
				
			} catch (Exception $e) {
				
			}
		}
		
		//is low S
		//$isLowDerSignature = $ecAdapter->validateSignatureElement($S, true); 
		?>
		<div class="alert alert-success">
			<b>Recovered Public Key</b>: <br/>
			<?php echo implode("<br/>", $publicKeys);?>
		</div>
		<?php
    } catch (Exception $e) {
        $errmsg .= "Problem found. " . $e->getMessage();
    }
} 

if ($errmsg) {
?>
    <div class="alert alert-danger">
        <strong>Error!</strong> <?php echo $errmsg?>
    </div>
<?php
}
?>
<form action='' method='post'>
	
	<div class="form-group">
        <label for="msg">Hash Message (Hex):</label>
        <input class="form-control" type='text' name='msg' id='msg' value='<?php echo $_POST['msg']?>'>
    </div>
	
	
	<div class="form-group">
        <label for="der">DER Signature:</label>
        <input class="form-control" type='text' name='der' id='der' value='<?php echo $_POST['der']?>'>
    </div>
    
	<div class="form-group">
        <label for="compression">Public Key:</label>
        <select name="compression" class="form-control" id='compression'>
            <?php
            $yesno = array("y"=>"Has Compression", "n"=>"Without Compression");
            foreach($yesno as $yesno_k=>$yesno_v) {
                echo "<option value='{$yesno_k}'".($yesno_k == $_POST['compression'] ? " selected": "").">{$yesno_v}</option>";
            }
            ?>
        </select>
    </div>
   
    <input type='submit' class="btn btn-success btn-block"/>
</form>
<?php
include_once("html_iframe_footer.php");		








Tutorials
About Us
Contents have been open source in GITHUB. Please give me a ⭐ if you found this helpful :)
Community
Problem? Raise me a new issue.
Support Us
Buy me a coffee. so i can spend more nights for this :)

BTCSCHOOLS would like to present you with more pratical but little theory throughout our tutorials. Pages' content are constantly keep reviewed to avoid mistakes, but we cannot warrant correctness of all contents. While using this site, you agree to accept our terms of use, cookie & privacy policy. Copyright 2019 by BTCSCHOOLS. All Rights Reserved.