function isMessageSignatureValid($address, $signature, $message) { $address = base58check_decode($address); if (strlen($address) != 21 || $address[0] != "") { throw new InvalidArgumentException('Invalid Bitcoin address.'); } $derivedAddress = getVerifiedAddress160Bin($signature, $message); $derivedAddress = "" . $derivedAddress; return $address === $derivedAddress; }
public function buildDataAddr($toaddr, $currency, $amount) { $decoded = base58check_decode($toaddr); $seqnum = hexdec(bin2hex($decoded[1])) - 1; if ($seqnum < 0) { $seqnum = $seqnum + 256; } $datahex = dechex($seqnum); // seqence number $datahex = $datahex . $this->int32ToHexLittle(0); // tx type $datahex = $datahex . $this->int32ToHexLittle($currency); // currency id $datahex = $datahex . $this->int64ToHexLittle($amount); // amount $datahex = $datahex . "000000"; $encoded = base58check_encode(hex2bin($datahex)); return $encoded; }
function isMessageSignatureValid($address, $signature, $message) { // curve definition // http://www.secg.org/download/aid-784/sec2-v2.pdf static $secp256k1 = null; static $secp256k1_G = null; $secp256k1 == null && ($secp256k1 = new CurveFp('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F', '0', '7')); $secp256k1_G == null && ($secp256k1_G = new Point($secp256k1, '0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798', '0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8', '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141')); // extract parameters $address = base58check_decode($address); if (strlen($address) != 21 || $address[0] != "") { throw new InvalidArgumentException('invalid Bitcoin address'); } $signature = base64_decode($signature, true); if ($signature === false) { throw new InvalidArgumentException('invalid base64 signature'); } if (strlen($signature) != 65) { throw new InvalidArgumentException('invalid signature length'); } $recoveryFlags = ord($signature[0]) - 27; if ($recoveryFlags < 0 || $recoveryFlags > 7) { throw new InvalidArgumentException('invalid signature type'); } $isCompressed = ($recoveryFlags & 4) != 0; // hash message, recover key $messageHash = hash('sha256', hash('sha256', "Bitcoin Signed Message:\n" . numToVarIntString(strlen($message)) . $message, true), true); $pubkey = recoverPubKey(bin2gmp(substr($signature, 1, 32)), bin2gmp(substr($signature, 33, 32)), bin2gmp($messageHash), $recoveryFlags, $secp256k1_G); if ($pubkey === false) { throw new InvalidArgumentException('unable to recover key'); } $point = $pubkey->getPoint(); // see that the key we recovered is for the address given if (!$isCompressed) { $pubBinStr = "" . str_pad(gmp2bin($point->getX()), 32, "", STR_PAD_LEFT) . str_pad(gmp2bin($point->getY()), 32, "", STR_PAD_LEFT); } else { $pubBinStr = (isBignumEven($point->getY()) ? "" : "") . str_pad(gmp2bin($point->getX()), 32, "", STR_PAD_LEFT); } $derivedAddress = "" . hash('ripemd160', hash('sha256', $pubBinStr, true), true); return $address === $derivedAddress; }
protected function addressToRipemd160($address) { return bin2hex(substr(base58check_decode($address), 1, 20)); }