def set_keyindex(self, x, keyindex, private_key): bip = bip32() address = bip.key_to_address( bip.derive_child(private_key, str(keyindex))) self.inputs[x]['keyindex'] = str(keyindex) self.inputs[x]['sigscript'] = unhexlify( '76a914' + hexlify(b58decode(address, None))[2:] + '88ac')
def ok(self): # Validate public key b32 = bip32() if b32.validate_ext_private_key(self.txtMasterPrivKey.toPlainText()) == False: QMessageBox.critical(self, "Error", "You did not specify a valid BIP32 private key. Please double check, and try again.") return # Get public key pubkey = b32.ext_private_to_public(self.txtMasterPrivKey.toPlainText()) self.txtMasterPubKey.setPlainText(pubkey)
def ok(self): # Initialize testnet = False b32 = bip32(testnet) # Generate master key privkey = b32.generate_master_key() pubkey = b32.ext_private_to_public(privkey) # Set textboxes self.txtMasterPrivKey.setPlainText(privkey) self.txtMasterPubKey.setPlainText(pubkey)
def ok(self): # Initialize b32 = bip32(False) # Validate private key if b32.validate_ext_private_key(self.txtMasterPrivKey.toPlainText()) == False: QMessageBox.critical(self, "Error", "You did not specify a valid BIP32 private key. Please double check, and try again.") # Generate master key privkey = b32.derive_child(self.txtMasterPrivKey.toPlainText(), self.txtKeyIndex.text(), True) pubkey = b32.ext_private_to_public(privkey) # Set textboxes self.txtChildPrivKey.setPlainText(privkey) self.txtChildPubKey.setPlainText(pubkey)
def ok(self): # Initialize b32 = bip32(False) # Validate private key if b32.validate_ext_private_key( self.txtMasterPrivKey.toPlainText()) == False: QMessageBox.critical( self, "Error", "You did not specify a valid BIP32 private key. Please double check, and try again." ) # Generate master key privkey = b32.derive_child(self.txtMasterPrivKey.toPlainText(), self.txtKeyIndex.text(), True) pubkey = b32.ext_private_to_public(privkey) # Set textboxes self.txtChildPrivKey.setPlainText(privkey) self.txtChildPubKey.setPlainText(pubkey)
def sign_transaction(self): # Go through inputs x = 0 fully_signed = True for item in self.inputs: hexcode = self.encode_transaction(x) + unhexlify('01000000') # Get pub keys from sigscript pubkeys = [] s = re.match(r'(..)(.*)(..)ae$', hexlify(item['sigscript']), re.M|re.I) if s: p = 0 sig = unhexlify(s.group(2)) reqsigs = (int(s.group(1)) - 50) while True: length = int(hexlify(sig[p:(p+1)]), 16) pubkeys.append(sig[(p+1):(p+length+1)]) p += (length + 1) if p >= len(sig): break else: pubkeys.append(item['sigscript']) reqsigs = 1 # Go through private keys, and get signatures self.inputs[x]['signatures'] = [] for privkey in item['privkeys']: # Decode child key bip = bip32() bip.decode_key(privkey) public_key = bip.private_to_public(bip.key, True) uncompressed_public_key = bip.private_to_public(bip.key) # Go through public keys for pkey in pubkeys: # Check public key if pkey != public_key and pkey != uncompressed_public_key and pkey != item['sigscript']: continue # Get hash hash = hashlib.sha256(hashlib.sha256(hexcode).digest()).digest() # Sign transaction signingkey = ecdsa.SigningKey.from_string(bip.key[1:], curve=ecdsa.SECP256k1) der = signingkey.sign_digest(hash, sigencode=ecdsa.util.sigencode_der) + unhexlify('01') der = self.verify_der(der) self.inputs[x]['signatures'].append(der) # Check # of signatures if len(self.inputs[x]['signatures']) >= reqsigs: # Create sig if len(self.inputs[x]['signatures']) > 1: full_sig = unhexlify("00") for sign in self.inputs[x]['signatures']: full_sig += self.encode_vint(len(sign)) + sign self.inputs[x]['sigscript'] = full_sig + unhexlify('4c') + self.encode_vint(len(item['sigscript'])) + item['sigscript'] else: self.inputs[x]['sigscript'] = self.encode_vint(len(self.inputs[x]['signatures'][0])) + self.inputs[x]['signatures'][0] self.inputs[x]['sigscript'] += self.encode_vint(len(public_key)) + public_key # Partial signatures else: fully_signed = False x += 1 # Done foreach loop here if fully_signed == True: return hexlify(self.encode_transaction()) else: return False
def set_keyindex(self, x, keyindex, private_key): bip = bip32() address = bip.key_to_address(bip.derive_child(private_key, str(keyindex))) self.inputs[x]['keyindex'] = str(keyindex) self.inputs[x]['sigscript'] = unhexlify('76a914' + hexlify(b58decode(address, None))[2:] + '88ac')
def sign_transaction(self): # Go through inputs x = 0 fully_signed = True for item in self.inputs: hexcode = self.encode_transaction(x) + unhexlify('01000000') # Get pub keys from sigscript pubkeys = [] s = re.match(r'(..)(.*)(..)ae$', hexlify(item['sigscript']), re.M | re.I) if s: p = 0 sig = unhexlify(s.group(2)) reqsigs = (int(s.group(1)) - 50) while True: length = int(hexlify(sig[p:(p + 1)]), 16) pubkeys.append(sig[(p + 1):(p + length + 1)]) p += (length + 1) if p >= len(sig): break else: pubkeys.append(item['sigscript']) reqsigs = 1 # Go through private keys, and get signatures self.inputs[x]['signatures'] = [] for privkey in item['privkeys']: # Decode child key bip = bip32() bip.decode_key(privkey) public_key = bip.private_to_public(bip.key, True) uncompressed_public_key = bip.private_to_public(bip.key) # Go through public keys for pkey in pubkeys: # Check public key if pkey != public_key and pkey != uncompressed_public_key and pkey != item[ 'sigscript']: continue # Get hash hash = hashlib.sha256( hashlib.sha256(hexcode).digest()).digest() # Sign transaction signingkey = ecdsa.SigningKey.from_string( bip.key[1:], curve=ecdsa.SECP256k1) der = signingkey.sign_digest( hash, sigencode=ecdsa.util.sigencode_der) + unhexlify('01') der = self.verify_der(der) self.inputs[x]['signatures'].append(der) # Check # of signatures if len(self.inputs[x]['signatures']) >= reqsigs: # Create sig if len(self.inputs[x]['signatures']) > 1: full_sig = unhexlify("00") for sign in self.inputs[x]['signatures']: full_sig += self.encode_vint(len(sign)) + sign self.inputs[x]['sigscript'] = full_sig + unhexlify( '4c') + self.encode_vint(len( item['sigscript'])) + item['sigscript'] else: self.inputs[x]['sigscript'] = self.encode_vint( len(self.inputs[x]['signatures'] [0])) + self.inputs[x]['signatures'][0] self.inputs[x]['sigscript'] += self.encode_vint( len(public_key)) + public_key # Partial signatures else: fully_signed = False x += 1 # Done foreach loop here if fully_signed == True: return hexlify(self.encode_transaction()) else: return False
def ok(self): # Initialize b32 = bip32() # Initial checks if self.lblImportFilename.text() == '' or not os.path.isfile(self.lblImportFilename.text()): QMessageBox.critical(self, "Error", "You did not specify a valid JSON file. Please ensure you select a JSON file, and try again.") return # Get JSON code fh = open(self.lblImportFilename.text(), 'r') try: self.json = json.load(fh) except: QMessageBox.critical(self, "Error", "Unable to load JSON file. Please ensure the JSON file is correctly formatted, and try again.") return fh.close() # Check BIP32 public / private key index if 'public_prefix' in self.json: b32.public_prefix = self.json['public_prefix'] if 'private_prefix' in self.json: b32.private_prefix = self.json['private_prefix'] # Validate private keys privkeys = [] for txt in self.txtPrivKeys: if str(txt.toPlainText()) == '': continue if b32.validate_ext_private_key(str(txt.toPlainText())) == False: QMessageBox.critical(self, "Error", "You did not specify a valid BIP32 private key. Please double check, and try again.") return privkeys.append(str(txt.toPlainText())) # Validate JSON file self.validate_json_file(privkeys) if len(self.json_errors) > 0: QMessageBox.critical(self, "Error", "One or more errors were found within your JSON file. You may download a JSON file detailing the errors if desired.") save_filename = QFileDialog.getSaveFileName(self, "Save Errors File", "errors.json", "JSON files (*.*)") if save_filename != '': with open(save_filename, 'w') as outfile: json.dump(self.json_errors, outfile) return # Set variables txfee = 0.0001 if not 'txfee' in self.json else float(self.json['txfee']) txfee_paidby = 'sender' if not 'txfee_paidby' in self.json else self.json['txfee_paidby'] results = {'tx': [], 'spent_inputs': [], 'change_inputs': [], 'partial_signatures': [] } if 'wallet_id' in self.json: results['wallet_id'] = self.json['wallet_id'] # Initialize testnet = True if 'testnet' in self.json and self.json['testnet'] == 1 else False b32 = bip32(testnet) # Go through outputs change_id = 0 if 'outputs' in self.json: for out in self.json['outputs']: # Initialize tx = rawtx() tx.__init__() # Blank variables input_amount = 0 output_amount = 0 has_change = False change_input = { } # Add outputs, as needed if 'recipients' in out: for recip in out['recipients']: send_amount = float(recip['amount']) if not txfee_paidby == 'recipient' else float(recip['amount']) - txfee tx.add_output(send_amount, recip['address']) output_amount += send_amount else: output_amount = float(out['amount']) if not txfee_paidby == 'recipient' else float(out['amount']) - txfee tx.add_output(output_amount, out['address']) # Gather inputs for tx while len(self.json['inputs']) > 0: item = self.json['inputs'].pop(0) tx.add_input(unhexlify(item['txid']), int(item['vout']), unhexlify(item['sigscript']), item['keyindex'], item['privkeys']) input_amount += float(item['amount']) # Mark input spent results['spent_inputs'].append(item) # Check for change transaction if input_amount >= float(output_amount) + txfee: change_amount = float(input_amount) - float(output_amount) if txfee_paidby == 'sender': change_amount -= txfee if float(0) >= float(change_amount): break # Get change key index if 'change_keyindex' in out and 'change_sigscript' in out: change_keyindex = out['change_keyindex'] change_sigscript = out['change_sigscript'] elif 'change_keyindex' in self.json and 'change_sigscript' in self.json: change_keyindex = self.json['change_keyindex'] change_sigscript = self.json['change_sigscript'] else: change_keyindex = item['keyindex'] change_sigscript = item['sigscript'] # Get change address change_address = b32.sigscript_to_address(change_sigscript) tx.add_output(change_amount, change_address) # Add change input to results has_change = True change_id += 1 change_input['input_id'] = 'c' + str(change_id) change_input['vout'] = 1 change_input['amount'] = change_amount change_input['address'] = change_address change_input['keyindex'] = change_keyindex change_input['sigscript'] = change_sigscript if change_sigscript == item['sigscript']: change_input['privkeys'] = item['privkeys'] change_input['reqsigs'] = item['reqsigs'] else: reqsigs, valid_privkeys = b32.validate_sigscript(change_sigscript, privkeys, change_keyindex) change_input['privkeys'] = valid_privkeys change_input['reqsigs'] = reqsigs break # Sign transaction trans = tx.sign_transaction() if trans == False: for item in tx.inputs: for sig in item['signatures']: results['partial_signatures'].append({'input_id': item['input_id'], 'signature': sig}) else: # Add to results txid = hexlify(hashlib.sha256(hashlib.sha256(unhexlify(trans)).digest()).digest()[::-1]) output_id = 0 if not 'output_id' in out else out['output_id'] tx_results = { 'output_id': str(output_id), 'txid': txid, 'amount': output_amount, 'input_amount': input_amount, 'to_address': out['recipients'], 'change_amount': change_amount, 'change_address': change_address, 'hexcode': trans } results['tx'].append(tx_results) # Add change input, if needed if has_change == True: change_input['txid'] = txid results['change_inputs'].append(change_input) self.json['inputs'].append(change_input) # Remove excess elements from inputs for item in results['spent_inputs']: if 'privkeys' in item: del item['privkeys'] if 'reqsigs' in item: del item['reqsigs'] for item in results['change_inputs']: if 'privkeys' in item: del item['privkeys'] if 'reqsigs' in item: del item['reqsigs'] # Show results w = import_tx_results() w.populate_results(results) self.parent.stack.addWidget(w) self.parent.stack.setCurrentWidget(w)
def validate_json_file(self, privkeys = []): # Initialize self.json_errors = [] b32 = bip32() # Check BIP32 public / private key index if 'public_prefix' in self.json: b32.public_prefix = self.json['public_prefix'] if 'private_prefix' in self.json: b32.private_prefix = self.json['private_prefix'] # Init a transaction tx = rawtx() tx.__init__() # Go through outputs for out in self.json['outputs']: if 'recipients' in out: for r in out['recipients']: if 'amount' not in r: self.add_json_error('no_variable', 'output', out['output_id'], 'amount') elif 'address' not in r: self.add_json_error('no_variable', 'output', out['output_id'], 'address') elif tx.validate_amount(r['amount']) == False: self.add_json_error('invalid_amount', 'output', out['output_id'], r['amount']) elif b32.validate_address(r['address']) == False: self.add_json_error('invalid_address', 'output', out['output_id'], r['address']) elif 'amount' not in out: self.add_json_error('no_variable', 'output', out['output_id'], 'amount') elif 'address' not in out: self.add_json_error('no_variable', 'output', out['output_id'], 'address') elif tx.validate_amount(out['amount']) == False: self.add_json_error('invalid_amount', 'output', out['output_id'], out['amount']) elif b32.validate_address(out['address']) == False: self.add_json_error('invalid_address', 'output', out['output_id'], out['address']) # Go through inputs x = 0 for item in self.json['inputs']: if 'amount' not in item: self.add_json_error('no_variable', 'input', item['input_id'], 'amount') elif 'txid' not in item: self.add_json_error('no_variable', 'input', item['input_id'], 'txid') elif 'vout' not in item: self.add_json_error('no_variable', 'input', item['input_id'], 'vout') elif 'sigscript' not in item: self.add_json_error('no_variable', 'input', item['input_id'], 'sigscript') elif 'keyindex' not in item: self.add_json_error('no_variable', 'input', item['input_id'], 'keyindex') elif tx.validate_amount(item['amount']) == False: self.add_json_error('invalid_amount', 'input', item['input_id'], item['amount']) # Validate vout try: int(item['vout']) except: self.add_json_error('invalid_vout', 'input', item['input_id'], input['vout']) # Get keyindexes if type(item['keyindex']) == str or type(item['keyindex']) == unicode: keyindexes = [item['keyindex']] elif type(item['keyindex']) == list: keyindexes = item['keyindex'] else: self.add_json_error('invalid_keyindex', 'input', item['input_id'], item['keyindex']) # Validate sigscript reqsigs, valid_privkeys = b32.validate_sigscript(item['sigscript'], privkeys, keyindexes) if valid_privkeys == False: self.add_json_error('invalid_sigscript', 'input', item['input_id'], item['sigscript']) else: self.json['inputs'][x]['privkeys'] = valid_privkeys self.json['inputs'][x]['reqsigs'] = reqsigs x += 1