From df0439bc23f51eb9c7696e880d40a6df4e17fac6 Mon Sep 17 00:00:00 2001 From: davidchocholaty Date: Fri, 8 Nov 2024 15:42:12 +0100 Subject: [PATCH] Add final version --- src/script.py | 108 +-------------------------------------------- src/transaction.py | 2 +- 2 files changed, 2 insertions(+), 108 deletions(-) diff --git a/src/script.py b/src/script.py index d468196..f3790b8 100644 --- a/src/script.py +++ b/src/script.py @@ -46,62 +46,7 @@ def __init__(self, script: bytes, json_transaction: dict = None, input_index: in def create_signature_hash(self, hash_type: int) -> bytes: data_signed = serialize_transaction(self.transaction, self.input_index, int(hash_type), self.segwit) return hashlib.sha256(data_signed).digest() - """ - Create the signature hash for the transaction based on the hash type. - This is what gets signed/verified in OP_CHECKSIG. - - if not self.transaction: - raise InvalidScriptException("No transaction context provided for signature verification") - - # Create a copy of the transaction - tx_copy = self.transaction.copy() - - # Clear all input scripts - for inp in tx_copy['vin']: - inp['scriptsig'] = '' - - # Handle different hash types - if hash_type & 0x1F == 0x01: # SIGHASH_ALL - # Most common, signs all inputs and outputs - # Current input gets the subscript - tx_copy['vin'][self.input_index]['scriptsig'] = self.script.hex() - - elif hash_type & 0x1F == 0x02: # SIGHASH_NONE - # Signs all inputs, but no outputs - tx_copy['vout'] = [] - # Zero out sequence numbers of other inputs - for i in range(len(tx_copy['vin'])): - if i != self.input_index: - tx_copy['vin'][i]['sequence'] = 0 - - elif hash_type & 0x1F == 0x03: # SIGHASH_SINGLE - # Signs all inputs and only the output with same index - if self.input_index >= len(tx_copy['vout']): - raise InvalidScriptException("SIGHASH_SINGLE invalid output index") - # Keep only the output at the same index - output = tx_copy['vout'][self.input_index] - tx_copy['vout'] = [{'value': -1, 'scriptpubkey': ''}] * self.input_index - tx_copy['vout'].append(output) - # Zero out sequence numbers of other inputs - for i in range(len(tx_copy['vin'])): - if i != self.input_index: - tx_copy['vin'][i]['sequence'] = 0 - - if hash_type & 0x80: # SIGHASH_ANYONECANPAY - # Only sign the current input - current_input = tx_copy['vin'][self.input_index] - tx_copy['vin'] = [current_input] - self.input_index = 0 - - # Serialize the modified transaction - serialized = self.serialize_transaction(tx_copy) - - # Add hash type - serialized += hash_type.to_bytes(4, 'little') - - # Double SHA256 - return hashlib.sha256(hashlib.sha256(serialized).digest()).digest() - """ + def serialize_transaction(self, tx: dict) -> bytes: """Serialize a transaction for signing/verification""" result = bytearray() @@ -357,57 +302,6 @@ def op_checksig(self) -> int: print(f"Unexpected exception: {e}") return 1 - def op_checkmultisig(self) -> int: - """ - Verify multiple signatures against multiple public keys - Returns number of bytes consumed - """ - if self.stack.size() < 1: - raise InvalidScriptException("Stack too small for CHECKMULTISIG") - - # Get number of public keys - n = int.from_bytes(self.stack.pop(), 'little') - if n < 0 or n > 20: - raise InvalidScriptException("Invalid number of public keys") - - if self.stack.size() < n + 1: - raise InvalidScriptException("Stack too small for public keys") - - # Get public keys - pubkeys = [] - for _ in range(n): - pubkeys.append(self.stack.pop()) - - # Get number of signatures - m = int.from_bytes(self.stack.pop(), 'little') - if m < 0 or m > n: - raise InvalidScriptException("Invalid number of signatures") - - if self.stack.size() < m: - raise InvalidScriptException("Stack too small for signatures") - - # Get signatures - signatures = [] - for _ in range(m): - signatures.append(self.stack.pop()) - - # Remove the extra null byte (Bitcoin protocol quirk) - if self.stack.size() < 1: - raise InvalidScriptException("No extra null byte for CHECKMULTISIG") - self.stack.pop() - - # TODO: Implement proper multisig verification - # This is a simplified version that always returns true - # In a real implementation, you would: - # 1. Verify each signature against public keys in order - # 2. Ensure all signatures are valid - # 3. Handle proper error cases - - verified = True # Replace with actual verification - - self.stack.push(b'\x01' if verified else b'\x00') - return 1 - @staticmethod def combine_scripts(*scripts: Union[bytes, 'Script'], json_transaction: dict, segwit: bool = False) -> 'Script': """ diff --git a/src/transaction.py b/src/transaction.py index c75b49d..e432cde 100644 --- a/src/transaction.py +++ b/src/transaction.py @@ -44,7 +44,7 @@ def __init__(self, transaction_json_file): def is_valid(self): # At least one input and one output. - if not self.non_empty_vin_vout(): + if not self.non_empty_vin_vout(): return False # Basic locktime check.