コード例 #1
0
ファイル: rawtx.py プロジェクト: blockplus/offline-singer
    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')
コード例 #2
0
	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)
コード例 #3
0
	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)
コード例 #4
0
    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)
コード例 #5
0
	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)
コード例 #6
0
    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)
コード例 #7
0
ファイル: rawtx.py プロジェクト: peterscott78/offline_signer
	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
コード例 #8
0
ファイル: rawtx.py プロジェクト: peterscott78/offline_signer
	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')
コード例 #9
0
ファイル: rawtx.py プロジェクト: blockplus/offline-singer
    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
コード例 #10
0
ファイル: import_tx.py プロジェクト: blockplus/offline-singer
	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)
コード例 #11
0
ファイル: import_tx.py プロジェクト: blockplus/offline-singer
	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