38 lines
1.1 KiB
PHP
38 lines
1.1 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Chain;
|
|
|
|
use Elliptic\EC;
|
|
use RuntimeException;
|
|
|
|
final class TronSigner
|
|
{
|
|
/**
|
|
* Sign a Tron txID (sha256 hex of raw_data) → 65-byte hex signature (r||s||v).
|
|
*/
|
|
public static function signTxId(string $privateKeyHex, string $txIdHex): string
|
|
{
|
|
// Tron full-node returns txID as 64-char hex (no 0x). Sign it as-is.
|
|
$raw = $txIdHex;
|
|
$txIdHex = strtolower(trim($txIdHex));
|
|
if (! preg_match('/^[0-9a-f]{64}$/', $txIdHex)) {
|
|
throw new RuntimeException(
|
|
'Invalid txID (len='.strlen($txIdHex).', raw_len='.strlen($raw).', value='.$raw.')'
|
|
);
|
|
}
|
|
|
|
$ec = new EC('secp256k1');
|
|
$key = $ec->keyFromPrivate($privateKeyHex);
|
|
$sig = $key->sign($txIdHex, ['canonical' => true]);
|
|
|
|
$r = str_pad($sig->r->toString(16), 64, '0', STR_PAD_LEFT);
|
|
$s = str_pad($sig->s->toString(16), 64, '0', STR_PAD_LEFT);
|
|
$v = dechex($sig->recoveryParam & 0xff);
|
|
if (strlen($v) === 1) {
|
|
$v = '0'.$v;
|
|
}
|
|
|
|
return $r.$s.$v;
|
|
}
|
|
}
|