def utxos(self): if self._outputs is None: import urllib.request import json url = network('utxo_url').format(address=self.address) req = urllib.request.Request(url) outputs = [] try: with urllib.request.urlopen(req) as resp: data = json.loads(resp.read().decode()) except HTTPError as e: resp = e.read().decode() if resp == 'No free outputs to spend': self._outputs = [] else: raise UpstreamError(resp) else: for item in data['unspent_outputs']: out = Output(value=item['value'], script=hex_to_bytes(item['script'])) out.parent_id = hex_to_bytes(item['tx_hash_big_endian']) out.tx_index = item['tx_output_n'] outputs.append(out) self._outputs = outputs return self._outputs
def asm(script): """Turns a script into a symbolic representation""" if isinstance(script, str): script = hex_to_bytes(script) else: script = copy(script) def read(n): nonlocal script data = script[:n] assert data or n == 0, 'EOF' script = script[n:] return data results = [] while script: byte = bytes_to_int(read(1)) op = OP(byte) if byte in range(1, 76): results.append(bytes_to_hex(read(byte))) elif byte == 76: bytes_to_read = bytes_to_int(read(1)) results.append(bytes_to_hex(read(bytes_to_read))) elif byte == 77: bytes_to_read = bytes_to_int(read(2)) results.append(bytes_to_hex(read(bytes_to_read))) elif byte == 78: bytes_to_read = bytes_to_int(read(4)) results.append(bytes_to_hex(read(bytes_to_read))) else: results.append(str(op)) return ' '.join(results)
def test_encoding(self): raw_sig = hex_to_bytes( '304402206878b5690514437a2342405029426cc2b25b4a03fc396fef845d656cf62bad2c022018610a8d37e3384245176ab49ddbdbe8da4133f661bf5ea7ad4e3d2b912d856f' ) sig = Signature.decode(raw_sig) self.assertEqual( sig.r, 47253809947851177065887724633329625063088643784040492056218945870752194997548 ) self.assertEqual( sig.s, 11026965355983493404719379810734327200902731292741433431270495068542334764399 ) self.assertEqual(sig.encode(), raw_sig) r = hex_to_int( '316eb3cad8b66fcf1494a6e6f9542c3555addbf337f04b62bf4758483fdc881d') s = hex_to_int( 'bf46d26cef45d998a2cb5d2d0b8342d70973fa7c3c37ae72234696524b2bc812') sig_high_s = hex_to_bytes( '30450220316eb3cad8b66fcf1494a6e6f9542c3555addbf337f04b62bf4758483fdc881d022100bf46d26cef45d998a2cb5d2d0b8342d70973fa7c3c37ae72234696524b2bc812' ) sig_low_s = hex_to_bytes( '30440220316eb3cad8b66fcf1494a6e6f9542c3555addbf337f04b62bf4758483fdc881d022040b92d9310ba26675d34a2d2f47cbd27b13ae26a7310f1c99c8bc83a850a792f' ) sig_high = Signature(r, s, force_low_s=False) sig_low = Signature(r, s, force_low_s=True) self.assertEqual(sig_low.encode(), sig_low_s) self.assertEqual(sig_high.encode(), sig_high_s) self.assertEqual(sig_low, Signature.decode(sig_high_s)) self.assertEqual(sig_low, Signature.decode(sig_low_s)) sig = Signature(secrets.randbelow(CURVE.N), secrets.randbelow(CURVE.N)) self.assertEqual(sig, Signature.decode(sig.encode())) # Test padding sig = Signature(secrets.randbelow(10**8), secrets.randbelow(10**8)) self.assertEqual(sig, Signature.decode(sig.encode()))
def from_seed(cls, seed: Union[bytes, str], addresstype='P2PKH') -> 'Xprv': if isinstance(seed, str): seed = hex_to_bytes(seed) assert 16 <= len(seed) <= 64, 'Seed should be between 128 and 512 bits' I = hmac.new(key=b"Bitcoin seed", msg=seed, digestmod=hashlib.sha512).digest() I_L, I_R = I[:32], I[32:] if bytes_to_int(I_L) == 0 or bytes_to_int(I_L) > CURVE.N: raise KeyDerivationError key, code = PrivateKey(I_L), I_R return cls(key, code, addresstype=addresstype)
def get_utxos(self, address): from cryptotools.BTC.transaction import Output url = self._get_url(self.UTXO_URLS) req = request.Request(url.format(address=address)) outputs = [] try: with request.urlopen(req) as resp: data = json.loads(resp.read().decode()) except HTTPError as e: resp = e.read().decode() if resp == 'No free outputs to spend': return [] else: raise UpstreamError(resp) else: for item in data['unspent_outputs']: out = Output(value=item['value'], script=hex_to_bytes(item['script'])) out.parent_id = hex_to_bytes(item['tx_hash_big_endian']) out.tx_index = item['tx_output_n'] outputs.append(out) return outputs
def get_utxos(self, address: str) -> List['Output']: from cryptotools.BTC.transaction import Output response = self.rpc_call('scantxoutset', ['start', [f"addr({address})"]])['result'] if not response['success']: raise UpstreamError(response['error']) outs = response['unspents'] outputs = [] for out in outs: sats = btc_to_satoshi(out['amount']) outputs.append(Output(value=sats, script=hex_to_bytes(out['scriptPubKey']))) return outputs
def get_address(script): """Extracts the address from a scriptPubkey""" script = hex_to_bytes(script) if isinstance(script, str) else script stype = get_type(script) if stype == TX.P2SH: data = script[2:22] version = network('scripthash') return hashed_payload_to_address(version + data) elif stype == TX.P2PKH: data = script[3:23] version = network('keyhash') return hashed_payload_to_address(version + data) elif stype in (TX.P2WSH, TX.P2WPKH): witver = version_byte(script) witprog = witness_program(script) return bech32.encode(network('hrp'), witver, witprog) elif stype == TX.P2PK: return "N/A" raise ValidationError(f"Unknown script type: {bytes_to_hex(script)}")
def get_utxos(self, address: str): from cryptotools.BTC.transaction import Output url = self._get_url(self.UTXO_URLS) req = request.Request(url.format(address=address)) outputs = [] try: with request.urlopen(req) as resp: data = json.loads(resp.read().decode()) except HTTPError as e: resp = e.read().decode() raise UpstreamError(resp) else: for item in data: out = Output(value=item['value'], script=b"") out.parent_id = hex_to_bytes(item['txid']) out.tx_index = item['vout'] outputs.append(out) return outputs
def get_type(script): """https://github.com/bitcoin/bitcoin/blob/5961b23898ee7c0af2626c46d5d70e80136578d3/src/script/script.cpp#L202""" script = hex_to_bytes(script) if isinstance(script, str) else script if script.startswith(OP.HASH160.byte + OP.PUSH20.byte) and script.endswith( OP.EQUAL.byte) and len(script) == 23: return TX.P2SH elif script.startswith(OP.DUP.byte + OP.HASH160.byte) and script.endswith( OP.EQUALVERIFY.byte + OP.CHECKSIG.byte) and len(script) == 25: return TX.P2PKH elif script.startswith(b'\x00' + OP.PUSH32.byte) and len(script) == 34: return TX.P2WSH elif script.startswith(b'\x00' + OP.PUSH20.byte) and len(script) == 22: return TX.P2WPKH elif script.startswith(OP.PUSH65.byte + b'\x04') and script.endswith( OP.CHECKSIG.byte) and len(script) == 67: # uncompressed PK return TX.P2PK elif script.startswith((b'\x21\x03', b'\x21\x02')) and script.endswith( OP.CHECKSIG.byte) and len(script) == 35: # compressed PK return TX.P2PK else: raise ScriptValidationError( f"Unknown script type: {bytes_to_hex(script)}")
def setUp(self) -> None: self.vectors = [] with open(HERE / 'vectors' / 'schnorr.csv', newline='') as csvfile: reader = csv.reader(csvfile) reader.__next__() for row in reader: (index, seckey_hex, pubkey_hex, aux_rand_hex, msg_hex, sig_hex, result_str, comment) = row msg = Message.from_hex(msg_hex) result = result_str == 'TRUE' aux = hex_to_bytes(aux_rand_hex) self.vectors.append({ 'index': index, 'pub': pubkey_hex, 'msg': msg, 'sig': sig_hex, 'result': result, 'prv': seckey_hex, 'aux': aux, 'comment': comment })
def from_hex(cls, hexstring): return cls.deserialize(hex_to_bytes(hexstring))
def redeem(self): if self.type() != 'P2SH': return None return hex_to_bytes(self.asm().split()[-1])
def from_hex(cls, hex): return cls.decode(hex_to_bytes(hex))
def from_hex(cls, hexstring): return cls.decode(hex_to_bytes(hexstring))
def from_hex(cls, hexstring: str) -> 'PublicKey': return cls.decode(hex_to_bytes(hexstring))