Esempio n. 1
0
    def sign(self, private, hashcode=SIGHASH.ALL):
        output_type = self.ref().type()
        if self.is_signed():
            raise SigningError('Input already signed')
        try:
            tx = self.parent
            idx = self.tx_index
            assert idx is not None
        except (AttributeError, AssertionError):
            raise SigningError("Reference to parent transaction missing")

        sighash = tx.sighash(idx, hashcode=hashcode)
        sig = private.sign_hash(sighash)

        # # https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki#low_s
        # if sig.s > CURVE.N//2:
        #     sig.s = CURVE.N - sig.s

        raw_sig = sig.encode() + hashcode.byte
        if output_type == TX.P2PKH:
            pub = private.to_public().encode(compressed=False)
            self.clear()
            self.script = push(raw_sig) + push(pub)
        elif output_type == TX.P2WPKH:
            pub = private.to_public().encode(compressed=True)
            self.clear()
            self.witness = (raw_sig, pub)
        elif output_type == TX.P2PK:
            self.clear()
            self.script = push(raw_sig)
        else:
            raise SigningError('Cannot sign P2SH or P2WSH outputs.')
Esempio n. 2
0
    def signature_form_segwit(self, i, hashcode=SIGHASH.ALL):
        """Segwit version of signature_form"""
        # https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification
        tx = deepcopy(self)

        ref = tx.inputs[i].ref()

        nversion = tx._version[::-1]
        hashprevouts = sha256(sha256(concat((inp.outpoint() for inp in tx.inputs)))) if not hashcode.is_anyonecanpay() else pad(0, 32)
        hashsequence = sha256(sha256(concat(inp._sequence[::-1] for inp in tx.inputs))) if hashcode == SIGHASH.ALL else pad(0, 32)
        outpoint = tx.inputs[i].outpoint()
        scriptcode = serialize(tx.inputs[i].scriptcode())
        value = ref._value[::-1]
        nsequence = tx.inputs[i]._sequence[::-1]

        if not (hashcode.is_single() or hashcode.is_none()):
            hashoutputs = sha256(sha256(concat(out._value[::-1] + push(out.script) for out in tx.outputs)))
        elif hashcode.is_single() and i < len(tx.outputs):
            hashoutputs = sha256(sha256(tx.outputs[i]._value[::-1] + push(tx.outputs[i].script)))
        else:
            hashoutputs = pad(0, 32)

        nlocktime = tx._lock_time[::-1]
        sighash = pad(hashcode.value, 4)[::-1]

        return concat([nversion, hashprevouts, hashsequence, outpoint, scriptcode, value, nsequence, hashoutputs, nlocktime, sighash])
Esempio n. 3
0
 def scriptcode(self):
     output = self.ref()
     output_type = self.ref().type()
     if output_type == TX.P2WPKH:
         return OP.DUP.byte + OP.HASH160.byte + push(witness_program(output.script)) + OP.EQUALVERIFY.byte + OP.CHECKSIG.byte
     elif output_type == TX.P2SH:
         if self.is_nested() == TX.P2WPKH:
             return OP.DUP.byte + OP.HASH160.byte + push(witness_program(self.script[1:])) + OP.EQUALVERIFY.byte + OP.CHECKSIG.byte
         elif self.is_nested() == TX.P2WSH:
             return self.witness[-1]
     # elif output_type == TX.P2WPKH:
     #     return output.script
     # elif output_type == TX.P2SH:
     #     return self.script
     elif output_type == TX.P2WSH:
         return self.witness[-1]
     else:
         raise ScriptValidationError(f"No scriptcode for {output_type}")
Esempio n. 4
0
 def _receive(self, value: int):
     """Creates an output that sends to this address"""
     addr_type = self.type()
     output = Output(value=value, script=b'')
     if addr_type == ADDRESS.P2PKH:
         address = base58.decode(self.address).rjust(25, b'\x00')
         keyhash = address[1:-4]
         output.script = OP.DUP.byte + OP.HASH160.byte + push(keyhash) + OP.EQUALVERIFY.byte + OP.CHECKSIG.byte
     elif addr_type == ADDRESS.P2SH:
         address = base58.decode(self.address).rjust(25, b'\x00')
         scripthash = address[1:-4]
         output.script = OP.HASH160.byte + push(scripthash) + OP.EQUAL.byte
     elif addr_type in (ADDRESS.P2WPKH, ADDRESS.P2WSH):
         witness_version, witness_program = bech32.decode(network('hrp'), self.address)
         output.script = OP(bytes_to_int(witness_byte(witness_version))).byte + push(bytes(witness_program))
     else:
         raise ValidationError(f"Cannot create output of type {addr_type}")
     return output
Esempio n. 5
0
def address_to_script(addr: str) -> bytes:
    """https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#segwit-address-format"""
    hrp, _ = bech32.bech32_decode(addr)
    if hrp not in [net['hrp'] for net in networks.values()]:
        raise Bech32DecodeError('Invalid human-readable part')
    witver, witprog = bech32.decode(hrp, addr)
    if not (0 <= witver <= 16):
        raise Bech32DecodeError('Invalid witness version')

    script = witness_byte(witver) + push(bytes(witprog))
    return script
Esempio n. 6
0
 def test_p2wsh(self):
     """https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#examples"""
     pubkey = PublicKey.from_hex(
         '0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798'
     )
     script = push(pubkey.encode(
         compressed=True)) + OP.CHECKSIG.byte  # <key> <OP_CHECKSIG>
     address = script_to_address(script, 'P2WSH')
     self.assertEqual(
         address,
         'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3')
     self.assertEqual(address_type(address), ADDRESS.P2WSH)
Esempio n. 7
0
def script_to_bech32(script: bytes, witver: int) -> str:
    """https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program"""
    witprog = sha256(script)
    return bech32.encode(network('hrp'), witver, witprog)


def pubkey_to_bech32(pub: PublicKey, witver: int) -> str:
    """https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program"""
    witprog = hash160(pub.encode(compressed=True))
    return bech32.encode(network('hrp'), witver, witprog)


key_to_addr_versions = {
    ADDRESS.P2PKH: lambda pub: legacy_address(pub, version_byte=network('keyhash')),
    # 'P2WPKH': partial(pubkey_to_p2wpkh, version_byte=0x06, witver=0x00),  # WAS REPLACED BY BIP 173
    ADDRESS.P2WPKH_P2SH: lambda pub: legacy_address(witness_byte(witver=0) + push(hash160(pub.encode(compressed=True))), version_byte=network('scripthash')),
    ADDRESS.P2WPKH: partial(pubkey_to_bech32, witver=0x00),
}

script_to_addr_versions = {
    ADDRESS.P2SH: lambda script: legacy_address(script, version_byte=network('scripthash')),
    # 'P2WSH': partial(script_to_p2wsh, version_byte=0x0A, witver=0x00),  # WAS REPLACED BY BIP 173
    ADDRESS.P2WSH_P2SH: lambda script: legacy_address(witness_byte(witver=0) + push(sha256(script)), version_byte=network('scripthash')),
    ADDRESS.P2WSH: partial(script_to_bech32, witver=0x00),
}


def pubkey_to_address(pub: PublicKey, version='P2PKH') -> str:
    converter = key_to_addr_versions[ADDRESS(version.upper())]
    return converter(pub)
Esempio n. 8
0
    def test_digest_p2sh_p2wsh(self):
        # https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#p2sh-p2wsh
        tx = Transaction.from_hex(
            '010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac00000000'
        )
        ref = Output(
            int(9.87654321 * 10**8),
            hex_to_bytes('a9149993a429037b5d912407a71c252019287b8d27a587'))

        inp = tx.inputs[0]
        inp._referenced_output = ref
        inp.script = push(
            hex_to_bytes(
                '0020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54'
            ))
        inp.witness = [
            hex_to_bytes(
                '56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae'
            )
        ]

        sighash = tx.sighash(0, hashcode=SIGHASH.ALL)
        self.assertEqual(
            bytes_to_hex(sighash),
            '185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c')

        sighash = tx.sighash(0, hashcode=SIGHASH.NONE)
        self.assertEqual(
            bytes_to_hex(sighash),
            'e9733bc60ea13c95c6527066bb975a2ff29a925e80aa14c213f686cbae5d2f36')

        sighash = tx.sighash(0, hashcode=SIGHASH.SINGLE)
        self.assertEqual(
            bytes_to_hex(sighash),
            '1e1f1c303dc025bd664acb72e583e933fae4cff9148bf78c157d1e8f78530aea')

        sighash = tx.sighash(0, hashcode=SIGHASH.ALL_ANYONECANPAY)
        self.assertEqual(
            bytes_to_hex(sighash),
            '2a67f03e63a6a422125878b40b82da593be8d4efaafe88ee528af6e5a9955c6e')

        sighash = tx.sighash(0, hashcode=SIGHASH.NONE_ANYONECANPAY)
        self.assertEqual(
            bytes_to_hex(sighash),
            '781ba15f3779d5542ce8ecb5c18716733a5ee42a6f51488ec96154934e2c890a')

        sighash = tx.sighash(0, hashcode=SIGHASH.SINGLE_ANYONECANPAY)
        self.assertEqual(
            bytes_to_hex(sighash),
            '511e8e52ed574121fc1b654970395502128263f62662e076dc6baf05c2e6a99b')

        signatures = [
            hex_to_bytes(
                '304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01'
            ),
            hex_to_bytes(
                '3044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502'
            ),
            hex_to_bytes(
                '3044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403'
            ),
            hex_to_bytes(
                '3045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381'
            ),
            hex_to_bytes(
                '3045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a0882'
            ),
            hex_to_bytes(
                '30440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783'
            )
        ]
        inp.witness = [b''] + signatures + inp.witness
        self.assertEqual(
            tx.hex(),
            '0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac080047304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01473044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502473044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403483045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381483045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a08824730440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000'
        )
        self.assertTrue(tx.verify())