public function sign($data)
{
if (!ctype_xdigit($this->hex)) {
throw new \Exception('The private key must be in hex format.');
}
if (empty($data)) {
throw new \Exception('You did not provide any data to sign.');
}
$e = Util::decodeHex(hash('sha256', $data));
do {
if (substr(strtolower($this->hex), 0, 2) != '0x') {
$d = '0x' . $this->hex;
} else {
$d = $this->hex;
}
$k = SecureRandom::generateRandom(32);
$k_hex = '0x' . strtolower(bin2hex($k));
$n_hex = '0x' . Secp256k1::N;
$Gx = '0x' . substr(Secp256k1::G, 2, 64);
$Gy = '0x' . substr(Secp256k1::G, 66, 64);
$P = new Point($Gx, $Gy);
// Calculate a new curve point from Q=k*G (x1,y1)
$R = Util::doubleAndAdd($k_hex, $P);
$Rx_hex = Util::encodeHex($R->getX());
$Rx_hex = str_pad($Rx_hex, 64, '0', STR_PAD_LEFT);
// r = x1 mod n
$r = Math::mod('0x' . $Rx_hex, $n_hex);
// s = k^-1 * (e+d*r) mod n
$edr = Math::add($e, Math::mul($d, $r));
$invk = Math::invertm($k_hex, $n_hex);
$kedr = Math::mul($invk, $edr);
$s = Math::mod($kedr, $n_hex);
// The signature is the pair (r,s)
$signature = array('r' => Util::encodeHex($r), 's' => Util::encodeHex($s));
$signature['r'] = str_pad($signature['r'], 64, '0', STR_PAD_LEFT);
$signature['s'] = str_pad($signature['s'], 64, '0', STR_PAD_LEFT);
} while (Math::cmp($r, '0') <= 0 || Math::cmp($s, '0') <= 0);
$sig = array('sig_rs' => $signature, 'sig_hex' => self::serializeSig($signature['r'], $signature['s']));
return $sig['sig_hex']['seq'];
}