예제 #1
0
    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
예제 #2
0
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)
예제 #3
0
    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()))
예제 #4
0
 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)
예제 #5
0
    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
예제 #6
0
    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
예제 #7
0
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)}")
예제 #8
0
    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
예제 #9
0
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)}")
예제 #10
0
    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
                })
예제 #11
0
 def from_hex(cls, hexstring):
     return cls.deserialize(hex_to_bytes(hexstring))
예제 #12
0
 def redeem(self):
     if self.type() != 'P2SH':
         return None
     return hex_to_bytes(self.asm().split()[-1])
예제 #13
0
 def from_hex(cls, hex):
     return cls.decode(hex_to_bytes(hex))
예제 #14
0
 def from_hex(cls, hexstring):
     return cls.decode(hex_to_bytes(hexstring))
예제 #15
0
 def from_hex(cls, hexstring: str) -> 'PublicKey':
     return cls.decode(hex_to_bytes(hexstring))