def derive_pubkey(message: str, signature: bytes) -> Tuple[bool, bytes]: """Derive a public key from a message and signature. Return a tuple (is_verified, public_key). The public key, is returned as a compressed key. If public_key is a null bytestring, it means deriving the public key from the signature failed. In this case is_verified is expected to be always False. If is_verified is True, it only means that this function was able to derive a public key from the message and signature. This public key still needs to be checked against another key or bitcoin address. """ h = bitcoin.Hash(bitcoin.msg_magic(message.encode("utf-8"))) try: public_key_from_sig, compressed = bitcoin.pubkey_from_signature( signature, h) except Exception: return False, b"" try: is_verified = public_key_from_sig.verify_digest( signature[1:], h, sigdecode=ecdsa.util.sigdecode_string) except Exception: is_verified = False return is_verified, public_key_from_sig.to_string(encoding="compressed")
def sign_message(self, sequence, message, password): sig = None try: inputPath = self.get_derivation() + "/%d/%d" % sequence inputHash = Hash(msg_magic(message)).encode('hex') hasharray = [] hasharray.append({'hash': inputHash, 'keypath': inputPath}) hasharray = json.dumps(hasharray) msg = '{"sign":{"meta":"sign message", "data":%s}}' % (hasharray) dbb_client = self.plugin.get_client(self) if not dbb_client.is_paired(): raise Exception("Could not sign message.") reply = dbb_client.hid_send_encrypt(msg) self.handler.show_message(_("Signing message ...\r\n\r\n" \ "To continue, touch the Digital Bitbox's blinking light for 3 seconds.\r\n\r\n" \ "To cancel, briefly touch the blinking light or wait for the timeout.")) reply = dbb_client.hid_send_encrypt( msg ) # Send twice, first returns an echo for smart verification (not implemented) self.handler.clear_dialog() if 'error' in reply: raise Exception(reply['error']['message']) if 'sign' not in reply: raise Exception("Could not sign message.") if 'recid' in reply['sign'][0]: # firmware > v2.1.1 sig = chr(27 + int(reply['sign'][0]['recid'], 16) + 4) + reply['sign'][0]['sig'].decode('hex') h = Hash(msg_magic(message)) pk, compressed = pubkey_from_signature(sig, h) pk = point_to_ser(pk.pubkey.point, compressed) addr = public_key_to_p2pkh(pk) if verify_message(addr, sig, message) is False: raise Exception("Could not sign message") elif 'pubkey' in reply['sign'][0]: # firmware <= v2.1.1 for i in range(4): sig = chr(27 + i + 4) + reply['sign'][0]['sig'].decode('hex') try: addr = public_key_to_p2pkh( reply['sign'][0]['pubkey'].decode('hex')) if verify_message(addr, sig, message): break except Exception: continue else: raise Exception("Could not sign message") except BaseException as e: self.give_error(e) return sig
def verify_signature(self, signature, message, verification_key): "This method verifies signature of message" pk, compressed = pubkey_from_signature(signature, Hash(msg_magic(message))) address_from_signature = public_key_to_p2pkh( point_to_ser(pk.pubkey.point, compressed)) address_from_vk = self.address(verification_key) return address_from_signature == address_from_vk
def verify_signature(self, signature, message, verification_key): "This method verifies signature of message" try: pk, compressed = pubkey_from_signature(signature, Hash(msg_magic(message))) pubkey = point_to_ser(pk.pubkey.point, compressed).hex() return pubkey == verification_key except Exception as e: self.print_error("verify_signature:", repr(e)) return False
def verify_signature(self, sig, message, vk): pk, compressed = pubkey_from_signature(sig,Hash(msg_magic(message))) address_from_signature = public_key_to_p2pkh(point_to_ser(pk.pubkey.point,compressed)) address_from_vk = self.address(vk) return address_from_signature == address_from_signature
def sign_message(self, sequence, message, password, sigtype=SignatureType.BITCOIN): if sigtype == SignatureType.ECASH: raise RuntimeError( _('eCash message signing is not available for {}').format( self.device)) sig = None try: message = message.encode('utf8') inputPath = self.get_derivation() + "/%d/%d" % sequence msg_hash = Hash(msg_magic(message)) inputHash = to_hexstr(msg_hash) hasharray = [] hasharray.append({'hash': inputHash, 'keypath': inputPath}) hasharray = json.dumps(hasharray) msg = b'{"sign":{"meta":"sign message", "data":%s}}' % hasharray.encode( 'utf8') dbb_client = self.plugin.get_client(self) if not dbb_client.is_paired(): raise Exception(_("Could not sign message.")) reply = dbb_client.hid_send_encrypt(msg) self.handler.show_message( _("Signing message ...") + "\n\n" + _("To continue, touch the Digital Bitbox's blinking light for 3 seconds." ) + "\n\n" + _("To cancel, briefly touch the blinking light or wait for the timeout." )) reply = dbb_client.hid_send_encrypt( msg ) # Send twice, first returns an echo for smart verification (not implemented) self.handler.finished() if 'error' in reply: raise Exception(reply['error']['message']) if 'sign' not in reply: raise Exception(_("Could not sign message.")) if 'recid' in reply['sign'][0]: # firmware > v2.1.1 sig = bytes([27 + int(reply['sign'][0]['recid'], 16) + 4 ]) + binascii.unhexlify(reply['sign'][0]['sig']) pk, compressed = pubkey_from_signature(sig, msg_hash) pk = point_to_ser(pk.pubkey.point, compressed) addr = public_key_to_p2pkh(pk) if verify_message(addr, sig, message) is False: raise Exception(_("Could not sign message")) elif 'pubkey' in reply['sign'][0]: # firmware <= v2.1.1 for i in range(4): sig = bytes([27 + i + 4]) + binascii.unhexlify( reply['sign'][0]['sig']) try: addr = public_key_to_p2pkh( binascii.unhexlify(reply['sign'][0]['pubkey'])) if verify_message(addr, sig, message): break except Exception: continue else: raise Exception(_("Could not sign message")) except BaseException as e: self.give_error(e) return sig
def verify_signature(self, signature, message, verification_key): "This method verifies signature of message" pk, compressed = pubkey_from_signature(signature, Hash(msg_magic(message))) pubkey = point_to_ser(pk.pubkey.point, compressed).hex() return pubkey == verification_key