<?php // Initialize global $template; // Update general settings if (isset($_POST['submit']) && $_POST['submit'] == tr('Add New Wallet')) { // Initialize $b32 = new bip32(); $enc_client = new encrypt(); $required_sigs = $_POST['address_type'] == 'standard' ? 1 : $_POST['multisig_sig_required']; $total_sigs = $_POST['address_type'] == 'standard' ? 1 : $_POST['multisig_sig_total']; // Validate public keys if ($_POST['autogen_keys'] == 0) { for ($x = 1; $x <= $total_sigs; $x++) { if (!($import = $b32->import($_POST['bip32_key' . $x]))) { $template->add_message("The #{$x} BIP32 key you specified is an invalid BIP32 key.", 'error'); } elseif ($import['type'] != 'public') { $template->add_message("The #{$x} BIP32 key you specified is an invalid BIP32 key.", 'error'); } } } // Create wallet, if no errors if ($template->has_errors != 1) { // Add to DB DB::insert('coin_wallets', array('address_type' => $_POST['address_type'], 'sigs_required' => $required_sigs, 'sigs_total' => $total_sigs, 'display_name' => $_POST['wallet_name'])); $wallet_id = DB::insertId(); // Gather BIP32 keys $keys = array(); for ($x = 1; $x <= $total_sigs; $x++) { // Auto-generate, if needed if ($_POST['autogen_keys'] == 1) {
public function sign_transaction($transaction, $inputs) { // Initialize $bip32 = new bip32(); // Start transaction $transaction[] = '01000000'; $orig_transaction = $transaction; // Add inputs temporarily $temp_input = 3; foreach ($inputs as $input) { // Set transaction variables $temp_transaction = $orig_transaction; if (count($input['privkeys']) > 1) { $temp_transaction[$temp_input] = $this->encode_vint(strlen(hex2bin($input['scriptsig']))); $temp_transaction[$temp_input + 1] = $input['scriptsig']; } else { $temp_transaction[$temp_input] = dechex(strlen(hex2bin($input['scriptsig']))); $temp_transaction[$temp_input + 1] = $input['scriptsig']; } // Initialize $generator = SECcurve::generator_secp256k1(); // Hash structure $temp_hex_trans = pack("H*", implode("", $temp_transaction)); $hash = hash('sha256', hash('sha256', $temp_hex_trans, true)); // Go through the keys $signatures = array(); $total_sign = 0; foreach ($input['privkeys'] as $privkey) { // Get public key $import = $bip32->import($privkey); $pubkey = $bip32->private_to_public($import['key']); $cpubkey = $bip32->private_to_public($import['key'], true); // Get ready to sign $point = new Point($generator->getCurve(), gmp_init(substr($pubkey, 2, 64), 16), gmp_init(substr($pubkey, 66, 64), 16), $generator->getOrder()); $_public_key = new PublicKey($generator, $point); $_private_key = new PrivateKey($_public_key, gmp_init($import['key'], 16)); // Sign $sign = $_private_key->sign(gmp_init($hash, 16), gmp_init((string) bin2hex(openssl_random_pseudo_bytes(32)), 16)); $signatures[$cpubkey] = $this->_encode_signature($sign); $total_sign++; } // Encode signature if (count($input['privkeys']) > 1) { $sig = '00'; foreach ($signatures as $pubkey => $sign) { $sig .= $this->encode_vint(strlen($sign) / 2) . $sign; } $sig .= '4c' . $this->encode_vint(strlen($input['scriptsig']) / 2) . $input['scriptsig']; } else { $key = array_keys($signatures)[0]; $sig = $this->encode_vint(strlen($signatures[$key]) / 2) . $signatures[$key]; $sig .= $this->encode_vint(strlen($key) / 2) . $key; } // Add to transaction $transaction[$temp_input] = $this->encode_vint(strlen(hex2bin($sig))); $transaction[$temp_input + 1] = $sig; $temp_input += 4; } array_pop($transaction); // Return return implode("", $transaction); }
} // Get address row if (!($addr_row = DB::queryFirstRow("SELECT * FROM coin_addresses WHERE address = %s", $row['address']))) { continue; } // Get keyindexes if ($wrow['address_type'] == 'multisig') { $keyindexes = array(); $public_keys = array(); $addr_rows = DB::query("SELECT * FROM coin_addresses_multisig WHERE address = %s ORDER BY id", $row['address']); foreach ($addr_rows as $arow) { $keyindexes[] = $addr_row['is_change_address'] . '/' . $arow['address_num']; // Get public key $ext_public_key = trim($encrypt->decrypt(DB::queryFirstField("SELECT public_key FROM coin_wallets_keys WHERE id = %d", $arow['key_id']))); $child_key = $bip32->build_key($ext_public_key, $addr_row['is_change_address'] . '/' . $arow['address_num'])[0]; $import = $bip32->import($child_key); $public_keys[] = $import['key']; } $sigscript = $bip32->create_redeem_script($wrow['sigs_required'], $public_keys); } else { $keyindexes = $addr_row['is_change_address'] . '/' . $addr_row['address_num']; $decode_address = $bip32->base58_decode($row['address']); $sigscript = '76a914' . substr($decode_address, 2, 40) . '88ac'; } // Set vars $vars = array('input_id' => $row['id'], 'amount' => $row['amount'], 'txid' => $row['txid'], 'vout' => $row['vout'], 'sigscript' => $sigscript, 'keyindex' => $keyindexes); array_push($json['inputs'], $vars); } // Gather outputs $rows = DB::query("SELECT * FROM coin_sends WHERE status = 'pending' ORDER BY id"); foreach ($rows as $row) {
// Create sigscript if ($wallet['address_type'] == 'multisig') { // Set variables $is_change = DB::queryFirstField("SELECT is_change_address FROM coin_addresses WHERE address = %s", $row['address']); // Get addresses $public_keys = array(); $keyindexes = array(); $addr_rows = DB::query("SELECT * FROM coin_addresses_multisig WHERE address = %s ORDER BY id", $row['address']); foreach ($addr_rows as $addr_row) { // Get public key & index $public_key = trim($enc->decrypt(DB::queryFirstField("SELECT public_key FROM coin_wallets_keys WHERE id = %d", $addr_row['key_id']))); $keyindex = $is_change . '/' . $addr_row['address_num']; $keyindexes[] = $keyindex; // Generate child key $child_ext_key = $bip32->build_key($public_key, $keyindex)[0]; $public_keys[] = $bip32->import($child_ext_key)['key']; } $scriptsig = $bip32->create_redeem_script($wallet['sigs_required'], $public_keys); $keyindex = implode(", ", $keyindexes); } else { $addr_row = DB::queryFirstRow("SELECT * FROM coin_addresses WHERE address = %s", $row['address']); $keyindex = $addr_row['is_change_address'] . '/' . $addr_row['address_num']; $decode_address = $bip32->base58_decode($row['address']); $scriptsig = '76a914' . substr($decode_address, 2, 40) . '88ac'; } // Add input $vars = array('input_id' => $row['id'], 'txid' => $row['txid'], 'vout' => $row['vout'], 'amount' => $row['amount'], 'keyindex' => $keyindex, 'scriptsig' => $scriptsig); array_push($inputs, $vars); $input_ids[] = $row['id']; } // Create transaction