示例#1
0
 /**
  * Sign
  *
  * This function accepts the same parameters as signrawtransaction.
  * $raw_transaction is a hex encoded string for an unsigned/partially
  * signed transaction. $inputs is an array, containing the txid/vout/
  * scriptPubKey/redeemscript. $priv_keys contains WIF keys.
  *
  * The function looks at each TxIn and tries to sign, if the hash160
  * belongs to a key specified in the wallet.
  *
  * @param   array $wallet
  * @param    string $raw_transaction
  * @param    array $inputs
  * @param    string $magic_byte
  * @return    array
  */
 public static function sign($wallet, $raw_transaction, $inputs, $magic_byte = '00')
 {
     // Generate digests of inputs to sign.
     $message_hash = self::_create_txin_signature_hash($raw_transaction, $inputs);
     $inputs_arr = (array) json_decode($inputs);
     // Generate an association of expected hash160's and related information.
     //$wallet = BitcoinLib::private_keys_to_receive($priv_keys);
     $decode = self::decode($raw_transaction);
     $req_sigs = 0;
     $sign_count = 0;
     foreach ($decode['vin'] as $vin => $input) {
         $scriptPubKey = self::_decode_scriptPubKey($inputs_arr[$vin]->scriptPubKey);
         $tx_info = self::_get_transaction_type($scriptPubKey, $magic_byte);
         if (isset($wallet[$tx_info['hash160']])) {
             $key_info = $wallet[$tx_info['hash160']];
             $generator = \SECcurve::generator_secp256k1();
             if ($key_info['type'] == 'scripthash') {
                 $signatures = self::extract_input_signatures_p2sh($input, $message_hash[$vin], $key_info);
                 $sign_count += count($signatures);
                 // Create Signature
                 foreach ($key_info['keys'] as $key) {
                     $point = new \Point($generator->getCurve(), gmp_init(substr($key['uncompressed_key'], 2, 64), 16), gmp_init(substr($key['uncompressed_key'], 66, 64), 16), $generator->getOrder());
                     $_public_key = new \PublicKey($generator, $point);
                     $_private_key = new \PrivateKey($_public_key, gmp_init($key['private_key'], 16));
                     $sign = $_private_key->sign(gmp_init($message_hash[$vin], 16), gmp_init((string) bin2hex(openssl_random_pseudo_bytes(32)), 16));
                     if ($sign !== FALSE) {
                         $sign_count++;
                         $signatures[$key['public_key']] = self::encode_signature($sign);
                     }
                 }
                 $decode['vin'][$vin]['scriptSig']['hex'] = self::_apply_sig_scripthash_multisig($signatures, $key_info);
                 // Increase required # signature counter.
                 $req_sigs += $key_info['required_signature_count'];
             }
             if ($key_info['type'] == 'pubkeyhash') {
                 // Create Signature
                 $point = new \Point($generator->getCurve(), gmp_init(substr($key_info['uncompressed_key'], 2, 64), 16), gmp_init(substr($key_info['uncompressed_key'], 66, 64), 16), $generator->getOrder());
                 $_public_key = new \PublicKey($generator, $point);
                 $_private_key = new \PrivateKey($_public_key, gmp_init($key_info['private_key'], 16));
                 $sign = $_private_key->sign(gmp_init($message_hash[$vin], 16), gmp_init((string) bin2hex(openssl_random_pseudo_bytes(32)), 16));
                 if ($sign !== FALSE) {
                     $sign_count++;
                     $decode['vin'][$vin]['scriptSig']['hex'] = self::_apply_sig_pubkeyhash(self::encode_signature($sign), $key_info['public_key']);
                 }
                 $req_sigs++;
             }
         }
     }
     $new_raw = self::encode($decode);
     // If the transaction isn't fully signed, return false.
     // If it's fully signed, perform signature verification, return true if valid, or invalid if signatures are incorrect.
     $complete = $req_sigs - $sign_count == 0 ? self::validate_signed_transaction($new_raw, $inputs, $magic_byte) == TRUE ? 'true' : 'false' : 'false';
     return array('hex' => $new_raw, 'complete' => $complete);
 }
示例#2
0
 /**
 * Generate a new private key
 *
 * @author Jacob Bruce
 * @return string
 * @access public
 */
 public static function getNewPrivKey()
 {
     $g = SECcurve::generator_secp256k1();
     $n = $g->getOrder();
     do {
         if (extension_loaded('gmp') && USE_EXT == 'GMP') {
             $privKey = gmp_Utils::gmp_random($n);
         } else {
             if (extension_loaded('bcmath') && USE_EXT == 'BCMATH') {
                 $privKey = bcmath_Utils::bcrand(1, $n);
             }
         }
         $privKeyHex = self::encodeHex($privKey);
     } while ($privKey < 1 || strlen($privKeyHex) > 64);
     return str_pad($privKeyHex, 64, '0', STR_PAD_LEFT);
 }
示例#3
0
 /**
  * Validate WIF
  * 
  * This function validates that a WIFs checksum validates, and that 
  * the private key is a valid number within the range 1 - n
  * 
  * $ver is unused at the moment.
  * 
  * @param	string	$wif
  * @param	string	$ver
  * @return	boolean
  */
 public static function validate_WIF($wif, $ver = null)
 {
     $hex = self::base58_decode($wif);
     // Learn checksum
     $crc = substr($hex, -8);
     $hex = substr($hex, 0, -8);
     // Learn version
     $version = substr($hex, 0, 2);
     $hex = substr($hex, 2);
     if ($ver !== NULL && $ver !== $version) {
         return FALSE;
     }
     // Determine if pubkey is compressed
     $compressed = FALSE;
     if (strlen($hex) == 66 && substr($hex, 64, 2) == '01') {
         $compressed = TRUE;
         $hex = substr($hex, 0, 64);
     }
     // Check private key within limit.
     $g = \SECcurve::generator_secp256k1();
     $n = $g->getOrder();
     if (gmp_strval(gmp_init($hex, 16), 10) >= $n) {
         return FALSE;
     }
     // Calculate checksum for what we have, see if it matches.
     $checksum = self::hash256($version . $hex . ($compressed ? '01' : ''));
     $checksum = substr($checksum, 0, 8);
     return $checksum == $crc;
 }
示例#4
0
 public function decompress_public_key($key)
 {
     // Initialize
     $y_byte = substr($key, 0, 2);
     $x_coordinate = substr($key, 2);
     // Set variables
     $x = gmp_strval(gmp_init($x_coordinate, 16), 10);
     $curve = SECcurve::curve_secp256k1();
     $generator = SECcurve::generator_secp256k1();
     // Decode
     try {
         $x3 = NumberTheory::modular_exp($x, 3, $curve->getPrime());
         $y2 = gmp_add($x3, $curve->getB());
         $y0 = NumberTheory::square_root_mod_prime(gmp_strval($y2, 10), $curve->getPrime());
         if ($y0 === false) {
             return false;
         }
         $y1 = gmp_strval(gmp_sub($curve->getPrime(), $y0), 10);
         $y_coordinate = $y_byte == '02' ? gmp_Utils::gmp_mod2(gmp_init($y0, 10), 2) == '0' ? $y0 : $y1 : (gmp_Utils::gmp_mod2(gmp_init($y0, 10), 2) !== '0' ? $y0 : $y1);
         $y_coordinate = str_pad(gmp_strval($y_coordinate, 16), 64, '0', STR_PAD_LEFT);
         $point = new Point($curve, gmp_strval(gmp_init($x_coordinate, 16), 10), gmp_strval(gmp_init($y_coordinate, 16), 10), $generator->getOrder());
     } catch (Exception $e) {
         return false;
     }
     // Return
     return array('x' => $x_coordinate, 'y' => $y_coordinate, 'point' => $point, 'public_key' => '04' . $x_coordinate . $y_coordinate);
 }
示例#5
0
 /**
  * Public Key From MPK
  * 
  * This function is used to generate a public key from the supplied
  * $mpk - the master public key, and an $iteration indicating which 
  * address in the sequence should be generated.
  * 
  * @param	string	$mpk
  * @param	int	$iteration
  * @return	string
  */
 public static function public_key_from_mpk($mpk, $iteration, $change = 0, $compressed = FALSE)
 {
     $change = $change == 0 ? '0' : '1';
     // Generate the curve, and the generator point.
     $curve = \SECcurve::curve_secp256k1();
     $gen = \SECcurve::generator_secp256k1();
     // Prepare the input values, by converting the MPK to X and Y coordinates
     $x = gmp_init(substr($mpk, 0, 64), 16);
     $y = gmp_init(substr($mpk, 64, 64), 16);
     // Generate a scalar from the $iteration and $mpk
     $z = gmp_init(hash('sha256', hash('sha256', "{$iteration}:{$change}:" . pack('H*', $mpk), TRUE)), 16);
     try {
         // Add the Point defined by $x and $y, to the result of EC multiplication of $z by $gen
         $pt = \Point::add(new \Point($curve, $x, $y), \Point::mul($z, $gen));
         // Generate the uncompressed public key.
         $keystr = '04' . str_pad(gmp_strval($pt->x, 16), 64, '0', STR_PAD_LEFT) . str_pad(gmp_strval($pt->y, 16), 64, '0', STR_PAD_LEFT);
     } catch (Exception $e) {
         throw new ErrorException($e->getMessage());
     }
     return $compressed == TRUE ? BitcoinLib::compress_public_key($keystr) : $keystr;
 }
示例#6
0
 /**
  * Check Valid HMAC Key
  * 
  * This function checks that the generated private keys meet the standard
  * for private keys, as imposed by the secp256k1 curve. The key can't
  * be zero, nor can it >= $n, which is the order of the secp256k1 
  * curve. Returning false trigger an error, or cause the program to
  * increase the address number and rerun the CKD function.
  * 
  * @param	string	$key
  * @return	boolean
  */
 public static function check_valid_hmac_key($key)
 {
     $g = \SECcurve::generator_secp256k1();
     $n = $g->getOrder();
     // initialize the key as a base 16 number.
     $g_l = gmp_init($key, 16);
     // compare it to zero
     $_equal_zero = gmp_cmp($g_l, gmp_init(0, 10));
     // compare it to the order of the curve
     $_GE_n = gmp_cmp($g_l, $n);
     if ($_equal_zero == 0 || $_GE_n == 1 || $_GE_n == 0) {
         return FALSE;
     }
     // Check for invalid data			// Exception?
     return TRUE;
 }
示例#7
0
 public function validate_signature($sig, $hash, $key)
 {
     // Initialize
     $signature = $this->decode_signature($sig);
     $test_signature = new Signature(gmp_init($signature['r'], 16), gmp_init($signature['s'], 16));
     $generator = SECcurve::generator_secp256k1();
     $curve = $generator->getCurve();
     // Check key
     if (strlen($key) == '66') {
         $client = new BIP32();
         $decompress = $client->decompress_public_key($key);
         $public_key_point = $decompress['point'];
     } else {
         $x = gmp_strval(gmp_init(substr($key, 2, 64), 16), 10);
         $y = gmp_strval(gmp_init(substr($key, 66, 64), 16), 10);
         $public_key_point = new Point($curve, $x, $y, $generator->getOrder());
     }
     // Get hash
     $public_key = new PublicKey($generator, $public_key_point);
     $hash = gmp_init($hash, 16);
     // Return
     return $public_key->verifies($hash, $test_signature) === true;
 }