def verify(self): txn = self.config.BU.get_transaction_by_id(self.id, instance=True) result = verify_signature(base64.b64decode(self.signature), self.id.encode('utf-8'), bytes.fromhex(txn.public_key)) if not result: raise Exception('Invalid external input')
def verify_ecdsa(message, signature, pub): """Checks if the signature from signEcdsa is correct.""" if not isinstance(message, (bytes, bytearray)): raise TypeError(f"Invalid message") if len(message) != 32: raise ValueError(f"Invalid length message: {len(message)} != 32") if not isinstance(signature, (bytes, bytearray)): raise TypeError(f"Invalid signature key") if len(signature) != 65: raise ValueError(f"Invalid length signature key: {len(signature)} != 65") if not isinstance(pub, (bytes, bytearray)): raise TypeError(f"Invalid signature key") if len(pub) != 64: raise ValueError(f"Invalid length signature key: {len(pub)} != 64") pubkey = PublicKey(b"\x04" + pub) r = _big_endian_to_int(signature[0:32]) s = _big_endian_to_int(signature[32:64]) low_s = _coerce_low_s(s) der_encoded_signature = bytes(_two_int_sequence_encoder(r, low_s)) return verify_signature( der_encoded_signature, message, pubkey.format(compressed=False), hasher=None )
async def recover_missing_transaction(self, txn_id, exclude_ids=[]): return False if await self.config.mongo.async_db.failed_recoveries.find_one({'txn_id': txn_id}): return False self.app_log.warning("recovering missing transaction input: {}".format(txn_id)) address = str(P2PKHBitcoinAddress.from_pubkey(bytes.fromhex(self.public_key))) missing_txns = self.config.mongo.async_db.blocks.aggregate([ { '$unwind': '$transactions' }, { '$project': { 'transaction': '$transactions', 'index': '$index' } } ], allowDiskUse=True) async for missing_txn in missing_txns: self.app_log.warning('recovery searching block index: {}'.format(missing_txn['index'])) try: result = verify_signature(base64.b64decode(txn_id), missing_txn['transaction']['hash'].encode(), bytes.fromhex(self.public_key)) if result: block_index = await self.find_unspent_missing_index(missing_txn['transaction']['hash'], exclude_ids) if block_index: await self.replace_missing_transaction_input( block_index, missing_txn['transaction']['hash'], txn_id ) return True else: if len(base64.b64decode(txn_id)) != 65: continue result = VerifyMessage( address, BitcoinMessage(missing_txn['transaction']['hash'], magic=''), txn_id ) if result: block_index = await self.find_unspent_missing_index(missing_txn['transaction']['hash'], exclude_ids) if block_index: await self.replace_missing_transaction_input( block_index, missing_txn['transaction']['hash'], txn_id ) return True except: continue await self.config.mongo.async_db.failed_recoveries.update_one({ 'txn_id': txn_id }, { '$set': { 'txn_id': txn_id } }, upsert=True) return False
async def connect(self, peer): try: id_attr = getattr(peer, peer.id_attribute) if id_attr in self.outbound_ignore[peer.__class__.__name__]: return if id_attr in self.outbound_pending[peer.__class__.__name__]: return if id_attr in self.outbound_streams[peer.__class__.__name__]: return if id_attr in self.config.nodeServer.inbound_pending[ peer.__class__.__name__]: return if id_attr in self.config.nodeServer.inbound_streams[ peer.__class__.__name__]: return if self.config.peer.identity.username_signature == peer.identity.username_signature: return if (self.config.peer.host, self.config.peer.host) == (peer.host, peer.port): return self.outbound_pending[peer.__class__.__name__][id_attr] = peer stream = await super(RPCSocketClient, self).connect(peer.host, peer.port, timeout=1) stream.synced = False stream.message_queue = {} stream.peer = peer try: result = verify_signature( base64.b64decode(stream.peer.identity.username_signature), stream.peer.identity.username.encode(), bytes.fromhex(stream.peer.identity.public_key)) if not result: self.config.app_log.warning( 'new {} peer signature is invalid'.format( peer.__class__.__name__)) stream.close() return self.config.app_log.info('new {} peer is valid'.format( peer.__class__.__name__)) except: self.config.app_log.warning('invalid peer identity signature') stream.close() return if id_attr in self.outbound_pending[peer.__class__.__name__]: del self.outbound_pending[peer.__class__.__name__][id_attr] self.outbound_streams[peer.__class__.__name__][id_attr] = stream self.config.app_log.info('Connected to {}: {}'.format( peer.__class__.__name__, peer.to_json())) return stream except StreamClosedError: await self.remove_peer(peer) self.config.app_log.warning('Streamed closed for {}: {}'.format( peer.__class__.__name__, peer.to_json())) except TimeoutError: await self.remove_peer(peer) self.config.app_log.warning('Timeout connecting to {}: {}'.format( peer.__class__.__name__, peer.to_json()))
def verify(self): txn = BU.get_transaction_by_id(self.config, self.mongo, self.id, instance=True) result = verify_signature(base64.b64decode(self.signature), self.id, txn.public_key.decode('hex')) if not result: raise Exception('Invalid external input')
def authenticate(self, session_id, post_data, hash_session_id=True): user = self.get_user(post_data) if hash_session_id: session_id = hashlib.sha256(session_id.encode()).hexdigest() result = verify_signature( base64.b64decode(post_data['session_id_signature']), session_id.encode(), bytes.fromhex(user.public_key) ) return user if result is True else None
async def authenticate(self, body, stream): signed_challenge = body.get('result', {}).get('signed_challenge') result = verify_signature( base64.b64decode(signed_challenge), stream.peer.token.encode(), bytes.fromhex(stream.peer.identity.public_key)) if result: stream.peer.authenticated = True self.config.app_log.info('Authenticated {}: {}'.format( stream.peer.__class__.__name__, stream.peer.to_json())) await self.send_block(self.config.LatestBlock.block) await self.get_next_block(self.config.LatestBlock.block) else: stream.close()
def verify_bis_signature(cls, signature: str, public_key: str, buffer: bytes, address: str = '') -> None: """Verify signature from bismuth tx network format (ecdsa sig and pubkey are b64 encoded) Returns None, but raises ValueError if needed.""" public_key = b64decode(public_key) valid = verify_signature(b64decode(signature), buffer, public_key) if not valid: raise ValueError(f"Invalid signature from {address}") # Reconstruct address from pubkey to make sure it matches if address != cls.public_key_to_address(public_key): raise ValueError("Attempt to spend from a wrong address")
def verify_bis_signature_raw(cls, signature: bytes, public_key: bytes, buffer: bytes, address: str = '') -> None: """Verify signature from bin format Returns None, but raises ValueError if needed.""" # print("ecdsa verify_bis_signature_raw pubkey", public_key, "sig", signature) valid = verify_signature(signature, buffer, public_key) if not valid: raise ValueError(f"Invalid signature from {address}") # Reconstruct address from pubkey to make sure it matches if address != cls.public_key_to_address(public_key): raise ValueError("Attempt to spend from a wrong address")
async def connect(self, body): params = body.get('params') if not params.get('identity'): self.close() return {} peer = User.from_dict({ 'host': None, 'port': None, 'identity': params.get('identity') }) self.peer = peer self.peer.groups = {} RCPWebSocketServer.inbound_streams[User.__name__][peer.rid] = self try: result = verify_signature( base64.b64decode(peer.identity.username_signature), peer.identity.username.encode(), bytes.fromhex(peer.identity.public_key)) if not result: self.close() except: self.config.app_log.error('invalid peer identity signature') self.close() return {} try: self.config.app_log.info('new {} is valid'.format( peer.__class__.__name__)) await self.write_result('connect_confirm', { 'identity': self.config.peer.identity.to_dict, 'shares_required': self.config.shares_required, 'credit_balance': await self.get_credit_balance(), 'server_pool_address': f'{self.config.peer_host}:{self.config.stratum_pool_port}' }, body=body) except: self.config.app_log.error('invalid peer identity signature') self.close() return {}
def verify(self): verify_hash = self.generate_hash() address = P2PKHBitcoinAddress.from_pubkey( self.public_key.decode('hex')) if verify_hash != self.hash: raise InvalidTransactionException("transaction is invalid") try: result = verify_signature( base64.b64decode(self.transaction_signature), self.hash, self.public_key.decode('hex')) if not result: raise except: try: result = VerifyMessage(address, BitcoinMessage(self.hash, magic=''), self.transaction_signature) if not result: raise except: raise InvalidTransactionSignatureException( "transaction signature did not verify") # verify spend total_input = 0 for txn in self.inputs: txn_input = Transaction.from_dict(BU.get_transaction_by_id(txn.id)) for output in txn_input.outputs: if str(output.to) == str(address): total_input += float(output.value) if self.coinbase: return total_output = 0 for txn in self.outputs: total_output += float(txn.value) total = float(total_output) + float(self.fee) if str(total_input) != str(total): raise BaseException( "inputs and outputs sum must match %s, %s, %s, %s" % (total_input, float(total_output), float(self.fee), total))
def __eq__(self, other: Any) -> bool: # For convenience of using stashed objects, we allow comparison with str if isinstance(other, str): othersig = Sig(other) else: othersig = cast(Sig, other) if self.sigval and othersig.sigval: return self.sigval == othersig.sigval elif not self.sigval and not othersig.sigval: return self.privkey == othersig.privkey and self.hashval == othersig.hashval elif not self.sigval: a = self b = othersig else: a = othersig b = self # A has a privkey/hash, B has a sigval. pubkey = coincurve.PublicKey.from_secret(a.privkey.secret) assert b.sigval is not None if coincurve.verify_signature(self.to_der(b.sigval), a.hashval, pubkey.format(), hasher=None): return True return False
async def connect(self, body, stream): params = body.get('params') if not params.get('peer'): stream.close() return {} generic_peer = Peer.from_dict(params.get('peer')) if isinstance(self.config.peer, Seed): if generic_peer.identity.username_signature in self.config.seeds: peerCls = Seed elif generic_peer.identity.username_signature in self.config.seed_gateways: peerCls = SeedGateway elif isinstance(self.config.peer, SeedGateway): if generic_peer.identity.username_signature in self.config.seeds: peerCls = Seed else: peerCls = ServiceProvider elif isinstance(self.config.peer, ServiceProvider): if generic_peer.identity.username_signature in self.config.seed_gateways: peerCls = SeedGateway else: peerCls = User elif isinstance(self.config.peer, User): peerCls = User else: self.config.app_log.error( 'inbound peer is not defined, disconnecting') stream.close() return {} limit = self.config.peer.__class__.type_limit(peerCls) if (len(NodeSocketServer.inbound_pending[peerCls.__name__]) + len( NodeSocketServer.inbound_streams[peerCls.__name__])) >= limit: await self.write_result(stream, 'capacity', {}, body['id']) stream.close() return {} try: stream.peer = peerCls.from_dict(params.get('peer')) except: self.config.app_log.error('invalid peer identity') stream.close() return {} if generic_peer.rid in NodeSocketServer.inbound_pending[ stream.peer.__class__.__name__]: stream.close() return {} if generic_peer.rid in NodeSocketServer.inbound_streams[ stream.peer.__class__.__name__]: stream.close() return {} if generic_peer.rid in self.config.nodeClient.outbound_ignore[ stream.peer.__class__.__name__]: stream.close() return if generic_peer.rid in self.config.nodeClient.outbound_pending[ stream.peer.__class__.__name__]: stream.close() return if generic_peer.rid in self.config.nodeClient.outbound_streams[ stream.peer.__class__.__name__]: stream.close() return try: result = verify_signature( base64.b64decode(stream.peer.identity.username_signature), stream.peer.identity.username.encode(), bytes.fromhex(stream.peer.identity.public_key)) if result: self.config.app_log.info('new {} peer is valid'.format( stream.peer.__class__.__name__)) except: self.config.app_log.error('invalid peer identity signature') stream.close() return {} NodeSocketServer.inbound_streams[peerCls.__name__][ stream.peer.rid] = stream self.config.app_log.info('Connected to {}: {}'.format( stream.peer.__class__.__name__, stream.peer.to_json())) return {}
async def verify(self): verify_hash = await self.generate_hash() address = P2PKHBitcoinAddress.from_pubkey( bytes.fromhex(self.public_key)) if verify_hash != self.hash: raise InvalidTransactionException("transaction is invalid") try: result = verify_signature( base64.b64decode(self.transaction_signature), self.hash.encode('utf-8'), bytes.fromhex(self.public_key)) if not result: print("t verify1") raise Exception() except: try: result = VerifyMessage(address, BitcoinMessage(self.hash, magic=''), self.transaction_signature) if not result: print("t verify2") raise except: print("t verify3") raise InvalidTransactionSignatureException( "transaction signature did not verify") if len(self.relationship) > 20480: raise MaxRelationshipSizeExceeded( 'Relationship field cannot be greater than 2048 bytes') # verify spend total_input = 0 exclude_recovered_ids = [] async for txn in self.get_inputs(self.inputs): input_txn = self.config.BU.get_transaction_by_id(txn.id) if input_txn: txn_input = Transaction.from_dict(input_txn) if not input_txn: if self.extra_blocks: txn_input = await self.find_in_extra_blocks(txn) if not txn_input: result = await self.recover_missing_transaction( txn.id, exclude_recovered_ids) exclude_recovered_ids.append(exclude_recovered_ids) raise MissingInputTransactionException( "Input not found on blockchain: {}".format(txn.id)) found = False for output in txn_input.outputs: if isinstance(txn, ExternalInput): ext_address = P2PKHBitcoinAddress.from_pubkey( bytes.fromhex(txn_input.public_key)) int_address = P2PKHBitcoinAddress.from_pubkey( bytes.fromhex(txn.public_key)) if str(output.to) == str(ext_address) and str( int_address) == str(txn.address): try: result = verify_signature( base64.b64decode(txn.signature), txn.id.encode('utf-8'), bytes.fromhex(txn_input.public_key)) if not result: print("t verify4") raise Exception() except: try: result = VerifyMessage( ext_address, BitcoinMessage(txn.id, magic=''), txn.signature) if not result: print("t verify5") raise except: raise InvalidTransactionSignatureException( "external input transaction signature did not verify" ) found = True total_input += float(output.value) elif str(output.to) == str(address): found = True total_input += float(output.value) if not found: if isinstance(txn, ExternalInput): raise InvalidTransactionException( "external input signing information did not match any recipients of the input transaction" ) else: raise InvalidTransactionException( "using inputs from a transaction where you were not one of the recipients." ) if self.coinbase: return total_output = 0 for txn in self.outputs: total_output += float(txn.value) total = float(total_output) + float(self.fee) if fix_float1(total_input) != fix_float1(total) and fix_float2( total_input) != fix_float2(total): raise TotalValueMismatchException( "inputs and outputs sum must match %s, %s, %s, %s" % (total_input, float(total_output), float(self.fee), total))
def verify(self): from yadacoin.fastgraph import FastGraph verify_hash = self.generate_hash() address = P2PKHBitcoinAddress.from_pubkey(bytes.fromhex(self.public_key)) if verify_hash != self.hash: raise InvalidTransactionException("transaction is invalid") try: result = verify_signature(base64.b64decode(self.transaction_signature), self.hash.encode('utf-8'), bytes.fromhex(self.public_key)) if not result: print("t verify1") raise Exception() except: try: result = VerifyMessage(address, BitcoinMessage(self.hash.encode('utf-8'), magic=''), self.transaction_signature) if not result: print("t verify2") raise except: print("t verify3") raise InvalidTransactionSignatureException("transaction signature did not verify") if len(self.relationship) > 2048: raise MaxRelationshipSizeExceeded('Relationship field cannot be greater than 2048 bytes') # verify spend total_input = 0 for txn in self.inputs: # TODO: move to async input_txn = self.config.BU.get_transaction_by_id(txn.id, include_fastgraph=isinstance(self, FastGraph)) if not input_txn: raise InvalidTransactionException("Input not found on blockchain.") txn_input = Transaction.from_dict(self.block_height, input_txn) found = False for output in txn_input.outputs: if isinstance(txn, ExternalInput): ext_address = P2PKHBitcoinAddress.from_pubkey(bytes.fromhex(txn_input.public_key)) int_address = P2PKHBitcoinAddress.from_pubkey(bytes.fromhex(txn.public_key)) if str(output.to) == str(ext_address) and str(int_address) == str(txn.address): try: result = verify_signature(base64.b64decode(txn.signature), txn.id.encode('utf-8'), bytes.fromhex(txn_input.public_key)) if not result: print("t verify4") raise Exception() except: try: result = VerifyMessage(ext_address, BitcoinMessage(txn.id, magic=''), txn.signature) if not result: print("t verify5") raise except: raise InvalidTransactionSignatureException("external input transaction signature did not verify") found = True total_input += float(output.value) elif str(output.to) == str(address): found = True total_input += float(output.value) if not found: if isinstance(txn, ExternalInput): raise InvalidTransactionException("external input signing information did not match any recipients of the input transaction") else: raise InvalidTransactionException("using inputs from a transaction where you were not one of the recipients.") if self.coinbase: return total_output = 0 for txn in self.outputs: total_output += float(txn.value) total = float(total_output) + float(self.fee) if "{0:.8f}".format(total_input) != "{0:.8f}".format(total): raise Exception("inputs and outputs sum must match %s, %s, %s, %s" % (total_input, float(total_output), float(self.fee), total))
def verify(self): from fastgraph import FastGraph verify_hash = self.generate_hash() address = P2PKHBitcoinAddress.from_pubkey( self.public_key.decode('hex')) if verify_hash != self.hash: raise InvalidTransactionException("transaction is invalid") try: result = verify_signature( base64.b64decode(self.transaction_signature), self.hash, self.public_key.decode('hex')) if not result: raise Exception() except: try: result = VerifyMessage(address, BitcoinMessage(self.hash, magic=''), self.transaction_signature) if not result: raise except: raise InvalidTransactionSignatureException( "transaction signature did not verify") # verify spend total_input = 0 for txn in self.inputs: input_txn = BU.get_transaction_by_id(self.config, self.mongo, txn.id, include_fastgraph=isinstance( self, FastGraph)) if not input_txn: raise InvalidTransactionException( "Input not found on blockchain.") txn_input = Transaction.from_dict(self.config, self.mongo, self.block_height, input_txn) found = False for output in txn_input.outputs: if hasattr(txn, 'public_key') and hasattr(txn, 'signature'): ext_address = P2PKHBitcoinAddress.from_pubkey( txn.public_key.decode('hex')) if str(output.to) == str(ext_address): found = True try: result = verify_signature( base64.b64decode(txn.signature), txn.id, txn.public_key.decode('hex')) if not result: raise Exception() except: try: result = VerifyMessage( ext_address, BitcoinMessage(txn.id, magic=''), txn.signature) if not result: raise except: raise InvalidTransactionSignatureException( "external input transaction signature did not verify" ) elif str(output.to) == str(address): found = True total_input += float(output.value) if not found: if hasattr(txn, 'public_key') and hasattr(txn, 'signature'): raise InvalidTransactionException( "external input signing information did not match any recipients of the input transaction" ) else: raise InvalidTransactionException( "using inputs from a transaction where you were not one of the recipients." ) if self.coinbase: return total_output = 0 for txn in self.outputs: total_output += float(txn.value) total = float(total_output) + float(self.fee) if "{0:.8f}".format(total_input) != "{0:.8f}".format(total): raise BaseException( "inputs and outputs sum must match %s, %s, %s, %s" % (total_input, float(total_output), float(self.fee), total))
def verify(self): return coincurve.verify_signature(bytes.fromhex(self.signature), self._signable(), bytes.fromhex(self.source))
async def connect(self, peer): try: stream = None id_attr = getattr(peer, peer.id_attribute) if id_attr in self.outbound_ignore[peer.__class__.__name__]: return if id_attr in self.outbound_pending[peer.__class__.__name__]: return if id_attr in self.outbound_streams[peer.__class__.__name__]: return if id_attr in self.config.nodeServer.inbound_pending[peer.__class__.__name__]: return if id_attr in self.config.nodeServer.inbound_streams[peer.__class__.__name__]: return if self.config.peer.identity.username_signature == peer.identity.username_signature: return if (self.config.peer.host, self.config.peer.host) == (peer.host, peer.port): return stream = DummyStream(peer) stream.last_activity = int(time.time()) self.outbound_pending[peer.__class__.__name__][id_attr] = stream stream = await super(RPCSocketClient, self).connect(peer.host, peer.port, timeout=timedelta(seconds=1)) stream.synced = False stream.syncing = False stream.message_queue = {} stream.peer = peer self.config.health.tcp_client.last_activity = time.time() stream.last_activity = int(time.time()) try: result = verify_signature( base64.b64decode(stream.peer.identity.username_signature), stream.peer.identity.username.encode(), bytes.fromhex(stream.peer.identity.public_key) ) if not result: self.config.app_log.warning('new {} peer signature is invalid'.format(peer.__class__.__name__)) stream.close() return self.config.app_log.info('new {} peer is valid'.format(peer.__class__.__name__)) except: self.config.app_log.warning('invalid peer identity signature') await self.remove_peer(stream) return if id_attr in self.outbound_pending[peer.__class__.__name__]: del self.outbound_pending[peer.__class__.__name__][id_attr] self.outbound_streams[peer.__class__.__name__][id_attr] = stream self.config.app_log.info('Connected to {}: {}'.format(peer.__class__.__name__, peer.to_json())) return stream except StreamClosedError: if not stream: stream = DummyStream(peer) await self.remove_peer(stream) self.config.app_log.warning('Streamed closed for {}: {}'.format(peer.__class__.__name__, peer.to_json())) except TimeoutError: if not stream: stream = DummyStream(peer) await self.remove_peer(stream) self.config.app_log.warning('Timeout connecting to {}: {}'.format(peer.__class__.__name__, peer.to_json())) except: if hasattr(stream, 'peer'): self.config.app_log.warning('Unhandled exception from {}: {}'.format(stream.peer.__class__.__name__, stream.peer.to_json())) await self.remove_peer(stream) self.config.app_log.debug("{}".format(format_exc()))