def verify_tx_signature(self, signature, transaction, verification_key, utxo): '''Verify the signature for a specific utxo ("prevout_hash:n") given a transaction and verification key.''' txin = list( filter( lambda x: (verification_key in x['pubkeys'] and utxo == "{}:{}".format( x['tx_hash'], x['tx_pos'])), transaction.inputs())) if txin: tx_num = transaction.inputs().index(txin[0]) pre_hash = Hash(bfh(transaction.serialize_preimage(tx_num))) order = generator_secp256k1.order() r, s = ecdsa.util.sigdecode_der(bfh(signature.decode()[:-2]), order) sig_string = ecdsa.util.sigencode_string(r, s, order) compressed = len(verification_key) <= 66 for recid in range(0, 4): try: pubk = MyVerifyingKey.from_signature(sig_string, recid, pre_hash, curve=SECP256k1) pubkey = bh2u(point_to_ser(pubk.pubkey.point, compressed)) if verification_key == pubkey: return True except: continue else: return False
def verify_tx_signature(self, signature, transaction, verification_key): "It verifies the transaction signatures" txin = list( filter(lambda x: verification_key in x['pubkeys'], transaction.inputs())) if txin: tx_num = transaction.inputs().index(txin[0]) pre_hash = Hash(bfh(transaction.serialize_preimage(tx_num))) order = generator_secp256k1.order() r, s = ecdsa.util.sigdecode_der(bfh(signature.decode()[:-2]), order) sig_string = ecdsa.util.sigencode_string(r, s, order) compressed = len(verification_key) <= 66 for recid in range(0, 4): try: pubk = MyVerifyingKey.from_signature(sig_string, recid, pre_hash, curve=SECP256k1) pubkey = bh2u(point_to_ser(pubk.pubkey.point, compressed)) if verification_key == pubkey: return True except: continue else: return False
def verify_tx_signature(signature, transaction, verification_key, utxo): '''Verify the signature for a specific utxo ("prevout_hash:n") given a transaction and verification key. Ensures that the signature is valid AND canonically encoded, so it will be accepted by network. ''' tx_num = None for n, x in enumerate(transaction.inputs()): if (verification_key in x['pubkeys'] and utxo == "{}:{}".format(x['tx_hash'], x['tx_pos'])): tx_num = n break else: # verification_key / utxo combo not found in tx inputs, bail return False # calculate sighash digest (implicitly this is for sighash 0x41) pre_hash = Hash(bfh(transaction.serialize_preimage(tx_num))) order = generator_secp256k1.order() try: sigbytes = bfh(signature.decode()) except ValueError: # not properly hex encoded or UnicodeDecodeError (garbage data) return False if not sigbytes or sigbytes[-1] != 0x41: return False DERsig = sigbytes[: -1] # lop off the sighash byte for the DER check below try: # ensure DER encoding is canonical, and extract r,s if OK r, s = CoinUtils.IsValidDERSignatureEncoding_With_Extract(DERsig) except AssertionError: return False if (s << 1) > order: # high S values are rejected by BCH network return False try: pubkey_point = ser_to_point(bfh(verification_key)) except: # ser_to_point will fail if pubkey is off-curve, infinity, or garbage. return False vk = MyVerifyingKey.from_public_point(pubkey_point, curve=SECP256k1) try: return vk.verify_digest(DERsig, pre_hash, sigdecode=ecdsa.util.sigdecode_der) except: # verify_digest returns True on success, otherwise raises return False
def __init__(self, window, wallet, network_settings, period = 10.0, logger = None, password=None, timeout=60.0, typ=Messages.DEFAULT # NB: Only DEFAULT is currently supported ): super().__init__() cls = type(self) self.daemon = True self.timeout = timeout self.version = cls.PROTOCOL_VERSION + (1 if networks.net.TESTNET else 0) self.type = typ assert self.type == Messages.DEFAULT, "BackgroundShufflingThread currently only supports DEFAULT shuffles" cls.latest_shuffle_settings = cls.ShuffleSettings(self.type, Messages.TYPE_NAME_DICT[self.type], self.version, 0, 0, self.FEE) # set UPPER_BOUND and LOWER_BOUND from config keys here. Note all instances will see these changes immediately. cls.update_lower_and_upper_bound_from_config() self.period = period self.logger = logger self.wallet = wallet self.window = window self.host = network_settings.get("host", None) self.info_port = network_settings.get("info", None) self.port = 1337 # default value -- will get set to real value from server's stat port in run() method self.poolSize = 3 # default value -- will get set to real value from server's stat port in run() method self.banScore = 0 # comes from stats port -- our own personal ban score self.banned = False # comes from stats port. True if our IP is banned (default ban duration: 30 mins) self.ssl = network_settings.get("ssl", None) self.lock = threading.RLock() self.password = password self.threads = {scale:None for scale in self.scales} self.shared_chan = Channel(switch_timeout=None) # threads write a 3-tuple here: (killme_flg, thr, msg) self.stop_flg = threading.Event() self.last_idle_check = 0.0 # timestamp in seconds unix time self.done_utxos = dict() self._paused = False self._coins_busy_shuffling = set() # 'prevout_hash:n' (name) set of all coins that are currently being shuffled by a ProtocolThread. Both wallet locks should be held to read/write this. self._last_server_check = 0.0 # timestamp in seconds unix time self._dummy_address = Address.from_pubkey(EC_KEY(number_to_string(1337, generator_secp256k1.order())).get_public_key()) # dummy address # below 4 vars are related to the "delayed unreserve address" mechanism as part of the bug #70 & #97 workaround and the complexity created by it.. self._delayed_unreserve_addresses = dict() # dict of Address -> time.time() timestamp when its shuffle ended self._last_delayed_unreserve_check = 0.0 # timestamp in seconds unix time self._delayed_unreserve_check_interval = 60.0 # check these addresses every 60 seconds. self._delayed_unreserve_timeout = 600.0 # how long before the delayed-unreserve addresses expire; 10 minutes