• About
  • FAQ
  • Earn Bitcoin while Surfing the net
  • Buy & Sell Crypto on Paxful
Newsletter
Approx Foundation
  • Home
    • Home – Layout 1
  • Bitcoin
  • Ethereum
  • Regulation
  • Market
  • Blockchain
  • Business
  • Guide
  • Contact Us
No Result
View All Result
  • Home
    • Home – Layout 1
  • Bitcoin
  • Ethereum
  • Regulation
  • Market
  • Blockchain
  • Business
  • Guide
  • Contact Us
No Result
View All Result
Approx Foundation
No Result
View All Result
Home Bitcoin

P2PKH Incomplete code

Moussa by Moussa
May 29, 2025
in Bitcoin
0
189
SHARES
1.5k
VIEWS
Share on FacebookShare on Twitter


import hashlib
import hmac
import requests

# Secp256k1 curve parameters
P = 2**256 - 2**32 - 977
N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
A = 0
B = 7
Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240
Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424
SIGHASH_ALL = 0x01

# Helper functions
def encode_base58(s, version_byte=b'\x6F'):  # Testnet version byte
    """Encode bytes to Base58Check (used for Bitcoin addresses)."""
    checksum = hashlib.sha256(hashlib.sha256(version_byte + s).digest()).digest()[:4]
    num = int.from_bytes(version_byte + s + checksum, 'big')
    alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
    base58 = ""
    while num:
        num, remainder = divmod(num, 58)
        base58 = alphabet[remainder] + base58
    # Add leading zeros for each leading zero byte
    for byte in (version_byte + s):
        if byte != 0:
            break
        base58 = alphabet[0] + base58
    return base58

def decode_base58(address, num_bytes=25):
    base58_chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
    base58_map = {char: index for index, char in enumerate(base58_chars)}
    num = 0
    for char in address:
        num *= 58
        if char not in base58_map:
            raise ValueError(f"Invalid Base58 character: {char}")
        num += base58_map[char]
    combined = num.to_bytes(num_bytes, byteorder="big")
    checksum = combined[-4:]
    payload = combined[:-4]
    if hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4] != checksum:
        raise ValueError("Invalid checksum")
    return payload[1:]  # Remove version byte

def hash160(data):
    return hashlib.new('ripemd160', hashlib.sha256(data).digest()).digest()

def hash256(s):
    return hashlib.sha256(hashlib.sha256(s).digest()).digest()

def encode_varint(n):
    if n < 253:
        return n.to_bytes(1, 'little')
    elif n < 65536:
        return b'\xfd' + n.to_bytes(2, 'little')
    elif n < 4294967296:
        return b'\xfe' + n.to_bytes(4, 'little')
    else:
        return b'\xff' + n.to_bytes(8, 'little')

def deterministic_k(secret, z):
    k = b'\x00' * 32
    v = b'\x01' * 32
    if z > N:
        z -= N
    z_bytes = z.to_bytes(32, 'big')
    secret_bytes = secret.to_bytes(32, 'big')
    k = hmac.new(k, v + b'\x00' + secret_bytes + z_bytes, hashlib.sha256).digest()
    v = hmac.new(k, v, hashlib.sha256).digest()
    k = hmac.new(k, v + b'\x01' + secret_bytes + z_bytes, hashlib.sha256).digest()
    v = hmac.new(k, v, hashlib.sha256).digest()
    while True:
        v = hmac.new(k, v, hashlib.sha256).digest()
        candidate = int.from_bytes(v, 'big')
        if 1 <= candidate < N:
            return candidate
        k = hmac.new(k, v + b'\x00', hashlib.sha256).digest()
        v = hmac.new(k, v, hashlib.sha256).digest()

# ECC Classes
class Point:
    def __init__(self, x, y, a, b):
        self.x = x
        self.y = y
        self.a = a
        self.b = b
        if x is not None and y is not None:
            if (y * y - (x * x * x + a * x + b)) % P != 0:
                raise ValueError("Point is not on the curve")

    def __add__(self, other):
        if self.x is None:
            return other
        if other.x is None:
            return self
        if self.x == other.x and self.y != other.y:
            return self.__class__(None, None, self.a, self.b)
        if self.x == other.x and self.y == other.y:
            if self.y == 0:
                return self.__class__(None, None, self.a, self.b)
            s = (3 * self.x * self.x + self.a) * pow(2 * self.y, P - 2, P) % P
        else:
            s = (other.y - self.y) * pow(other.x - self.x, P - 2, P) % P
        x = (s * s - self.x - other.x) % P
        y = (s * (self.x - x) - self.y) % P
        return self.__class__(x, y, self.a, self.b)

    def __rmul__(self, coefficient):
        coef = coefficient % N
        current = self
        result = self.__class__(None, None, self.a, self.b)
        while coef:
            if coef & 1:
                result = result + current
            current = current + current
            coef >>= 1
        return result

    def sec(self, compressed=True):
        if self.x is None:
            raise ValueError("Cannot serialize point at infinity")
        if compressed:
            prefix = b'\x02' if self.y % 2 == 0 else b'\x03'
            return prefix + self.x.to_bytes(32, 'big')
        else:
            return b'\x04' + self.x.to_bytes(32, 'big') + self.y.to_bytes(32, 'big')

G = Point(Gx, Gy, A, B)

class PrivateKey:
    def __init__(self, secret):
        self.secret = secret
        self.point = secret * G

    def sign(self, z):
        k = deterministic_k(self.secret, z)
        r = (k * G).x % N
        k_inv = pow(k, N - 2, N)
        s = (z + r * self.secret) * k_inv % N
        if s > N / 2:
            s = N - s
        return Signature(r, s)

class Signature:
    def __init__(self, r, s):
        self.r = r
        self.s = s

    def der(self):
        r_bin = self.r.to_bytes(32, "big").lstrip(b"\x00")
        if r_bin[0] & 0x80:
            r_bin = b"\x00" + r_bin
        s_bin = self.s.to_bytes(32, "big").lstrip(b"\x00")
        if s_bin[0] & 0x80:
            s_bin = b"\x00" + s_bin
        result = bytes([0x02, len(r_bin)]) + r_bin + bytes([0x02, len(s_bin)]) + s_bin
        return bytes([0x30, len(result)]) + result

class Script:
    def __init__(self, commands):
        self.commands = commands

    def serialize(self):
        result = b""
        for cmd in self.commands:
            if isinstance(cmd, int):
                result += bytes([cmd])
            elif isinstance(cmd, bytes):
                data_len = len(cmd)
                if data_len <= 75:
                    result += bytes([data_len]) + cmd
                elif data_len <= 255:
                    result += bytes([0x4c]) + bytes([data_len]) + cmd
                elif data_len <= 65535:
                    result += bytes([0x4d]) + data_len.to_bytes(2, 'little') + cmd
                else:
                    result += bytes([0x4e]) + data_len.to_bytes(4, 'little') + cmd
        return result

def p2pkh_script(hash160):
    return Script([0x76, 0xa9, hash160, 0x88, 0xac])

class TxIn:
    def __init__(self, prev_tx, prev_index):
        self.prev_tx = prev_tx
        self.prev_index = prev_index
        self.script_sig = Script([])
        self.sequence = b"\xff\xff\xff\xff"

class TxOut:
    def __init__(self, amount, script_pubkey):
        self.amount = amount
        self.script_pubkey = script_pubkey

class Tx:
    def __init__(self, version, tx_ins, tx_outs, locktime, testnet=False):
        self.version = version
        self.tx_ins = tx_ins
        self.tx_outs = tx_outs
        self.locktime = locktime
        self.testnet = testnet

    def sig_hash(self, index, prev_script_pubkey):
        result = self.version.to_bytes(4, "little")
        result += encode_varint(len(self.tx_ins))
        for i, tx_in in enumerate(self.tx_ins):
            result += tx_in.prev_tx[::-1]
            result += tx_in.prev_index.to_bytes(4, "little")
            if i == index:
                serialized_script = prev_script_pubkey.serialize()
                result += encode_varint(len(serialized_script))
                result += serialized_script
            else:
                result += b"\x00"
            result += tx_in.sequence
        result += encode_varint(len(self.tx_outs))
        for tx_out in self.tx_outs:
            result += tx_out.amount.to_bytes(8, "little")
            serialized_script = tx_out.script_pubkey.serialize()
            result += encode_varint(len(serialized_script))
            result += serialized_script
        result += self.locktime.to_bytes(4, "little")
        result += SIGHASH_ALL.to_bytes(4, "little")
        return int.from_bytes(hash256(result), "big")

    def serialize(self):
        result = self.version.to_bytes(4, "little")
        result += encode_varint(len(self.tx_ins))
        for tx_in in self.tx_ins:
            result += tx_in.prev_tx[::-1]
            result += tx_in.prev_index.to_bytes(4, "little")
            serialized_script = tx_in.script_sig.serialize()
            result += encode_varint(len(serialized_script))
            result += serialized_script
            result += tx_in.sequence
        result += encode_varint(len(self.tx_outs))
        for tx_out in self.tx_outs:
            result += tx_out.amount.to_bytes(8, "little")
            serialized_script = tx_out.script_pubkey.serialize()
            result += encode_varint(len(serialized_script))
            result += serialized_script
        result += self.locktime.to_bytes(4, "little")
        return result

# Main script
if __name__ == "__main__":
    # Step 1: Define the Input
    prev_tx = bytes.fromhex("27e97f3486ef5f837503d53aeeab6577b606e5bf71895fef4453702c4fc7bcea")
    prev_index = 1
    tx_in = TxIn(prev_tx, prev_index)

    # Step 2: Calculate Amounts
    fee = 2000
    utxo_amount = 59999
    target_amount = utxo_amount - fee  # 112541 satoshis
    print(f"Target amount to send: {target_amount} satoshis")

    # Step 3: Define the Single Target Output
    target_address = "mu6Hgf5PNLxq4y3dBZt8WyXt4fKG5JrKGj"
    target_h160 = decode_base58(target_address)
    target_script = p2pkh_script(target_h160)
    target_output = TxOut(amount=target_amount, script_pubkey=target_script)

    # Step 4: Create the Transaction with One Output
    tx_obj = Tx(version=1, tx_ins=[tx_in], tx_outs=[target_output], locktime=0, testnet=True)

    # Step 5: Derive Private Key and Public Key
    passphrase = b"652025"
    secret = int.from_bytes(hash256(passphrase), 'big')
    private_key = PrivateKey(secret=secret)
    sec = private_key.point.sec(compressed=True)

    # Step 6: Generate UTXO Address from Private Key
    pubkey_hash160 = hash160(sec)
    utxo_address = encode_base58(pubkey_hash160, version_byte=b'\x6F')  # Testnet
    print(f"Generated UTXO address: {utxo_address}")
    utxo_h160 = pubkey_hash160  # Use directly, no need to decode
    prev_script_pubkey = p2pkh_script(utxo_h160)

    # Step 7: Sign the Transaction
    z = tx_obj.sig_hash(0, prev_script_pubkey)
    print(f"Computed sig_hash: {z}")
    signature = private_key.sign(z)
    der = signature.der()
    print(f"DER Signature: {der.hex()}")
    sig = der + SIGHASH_ALL.to_bytes(1, "big")

    # Step 8: Verify Public Key Matches UTXO
    print(f"Public key hash160: {pubkey_hash160.hex()}")
    print(f"UTXO hash160: {utxo_h160.hex()}")
    print(f"Matches UTXO hash160: {pubkey_hash160 == utxo_h160}")  # Should always be True
    if not pubkey_hash160 == utxo_h160:
        print("Error: Generated public key does not match UTXO address!")
        exit(1)

    # Step 9: Construct scriptSig
    script_sig = Script([sig, sec])
    tx_obj.tx_ins[0].script_sig = script_sig
    print(f"ScriptSig: {script_sig.serialize().hex()}")

    # Step 10: Serialize the Transaction
    serialized_tx = tx_obj.serialize().hex()
    print(f"Serialized Transaction: {serialized_tx}")

    # Step 11: Broadcast the Transaction
    url = "https://api.blockchair.com/bitcoin/testnet/push/transaction"
    headers = {'Content-Type': 'application/json'}
    data = {"tx": serialized_tx}
    response = requests.post(url, json=data, headers=headers)
    if response.status_code == 200:
        print("Transaction successfully broadcasted.")
        print(f"Transaction ID: {response.json().get('data', {}).get('transaction_hash')}")
    else:
        print(f"Failed to broadcast transaction (Blockchair): {response.text}")
        url = "https://blockstream.info/testnet/api/tx"
        response = requests.post(url, data=serialized_tx)
        if response.status_code == 200:
            print("Transaction successfully broadcasted (Blockstream).")
            print(f"Transaction ID: {response.text}")
        else:
            print(f"Failed to broadcast transaction (Blockstream): {response.text}")

I successfully broadcasted this transaction but my code is not fully completed(like combined command set,push opcodes etc.

Related articles

Adam Back Confirmed As A Bitcoin 2026 Speaker

Adam Back Confirmed As A Bitcoin 2026 Speaker

March 20, 2026
Bank Executive Reinforces Bolivia’s Cryptocurrency Pivot Relevance Amidst Dollar Drought

Bank Executive Reinforces Bolivia’s Cryptocurrency Pivot Relevance Amidst Dollar Drought

March 20, 2026



Source link

Share76Tweet47

Related Posts

Adam Back Confirmed As A Bitcoin 2026 Speaker

Adam Back Confirmed As A Bitcoin 2026 Speaker

by Moussa
March 20, 2026
0

Adam Back has been officially confirmed as a speaker at Bitcoin 2026, returning to the conference as one of the...

Bank Executive Reinforces Bolivia’s Cryptocurrency Pivot Relevance Amidst Dollar Drought

Bank Executive Reinforces Bolivia’s Cryptocurrency Pivot Relevance Amidst Dollar Drought

by Moussa
March 20, 2026
0

Alvaro Rosenblüth, treasury and exchange manager at Banco de Crédito de Bolivia, stated that the Central Bank of Bolivia lifted...

How do Bitcoin mining pools typically handle payout frequency versus thresholds?

How long should pruning take?

by Moussa
March 20, 2026
0

How long should pruning—say, from 794GB blockchain down to last 2GB—take? Source link

Nasdaq Wins SEC Approval for Tokenized Securities: Wall Street Goes On-Chain

Nasdaq Wins SEC Approval for Tokenized Securities: Wall Street Goes On-Chain

by Moussa
March 20, 2026
0

Nasdaq has received SEC approval to launch a pilot program for trading tokenized securities, marking a significant move for Wall...

Bitcoin-Gold Correlation Plunges To -0.88, Lowest Since 2022

Bitcoin-Gold Correlation Plunges To -0.88, Lowest Since 2022

by Moussa
March 20, 2026
0

Trusted Editorial content, reviewed by leading industry experts and seasoned editors. Ad Disclosure Bitcoin is strongly moving in the opposite...

Load More

youssufi.com

sephina.com

[vc_row full_width="stretch_row" parallax="content-moving" vc_row_background="" background_repeat="no-repeat" background_position="center center" footer_scheme="dark" css=".vc_custom_1517813231908{padding-top: 60px !important;padding-bottom: 30px !important;background-color: #191818 !important;background-position: center;background-repeat: no-repeat !important;background-size: cover !important;}" footer_widget_title_color="#fcbf46" footer_button_bg="#fcb11e"][vc_column width="1/4"]

We bring you the latest in Crypto News

[/vc_column][vc_column width="1/4"][vc_wp_categories]
[/vc_column][vc_column width="1/4"][vc_wp_tagcloud taxonomy="post_tag"][/vc_column][vc_column width="1/4"]

Newsletter

[vc_raw_html]JTNDcCUzRSUzQ2RpdiUyMGNsYXNzJTNEJTIydG5wJTIwdG5wLXN1YnNjcmlwdGlvbiUyMiUzRSUwQSUzQ2Zvcm0lMjBtZXRob2QlM0QlMjJwb3N0JTIyJTIwYWN0aW9uJTNEJTIyaHR0cHMlM0ElMkYlMkZhcHByb3gub3JnJTJGJTNGbmElM0RzJTIyJTNFJTBBJTBBJTNDaW5wdXQlMjB0eXBlJTNEJTIyaGlkZGVuJTIyJTIwbmFtZSUzRCUyMm5sYW5nJTIyJTIwdmFsdWUlM0QlMjIlMjIlM0UlM0NkaXYlMjBjbGFzcyUzRCUyMnRucC1maWVsZCUyMHRucC1maWVsZC1maXJzdG5hbWUlMjIlM0UlM0NsYWJlbCUyMGZvciUzRCUyMnRucC0xJTIyJTNFRmlyc3QlMjBuYW1lJTIwb3IlMjBmdWxsJTIwbmFtZSUzQyUyRmxhYmVsJTNFJTBBJTNDaW5wdXQlMjBjbGFzcyUzRCUyMnRucC1uYW1lJTIyJTIwdHlwZSUzRCUyMnRleHQlMjIlMjBuYW1lJTNEJTIybm4lMjIlMjBpZCUzRCUyMnRucC0xJTIyJTIwdmFsdWUlM0QlMjIlMjIlM0UlM0MlMkZkaXYlM0UlMEElM0NkaXYlMjBjbGFzcyUzRCUyMnRucC1maWVsZCUyMHRucC1maWVsZC1lbWFpbCUyMiUzRSUzQ2xhYmVsJTIwZm9yJTNEJTIydG5wLTIlMjIlM0VFbWFpbCUzQyUyRmxhYmVsJTNFJTBBJTNDaW5wdXQlMjBjbGFzcyUzRCUyMnRucC1lbWFpbCUyMiUyMHR5cGUlM0QlMjJlbWFpbCUyMiUyMG5hbWUlM0QlMjJuZSUyMiUyMGlkJTNEJTIydG5wLTIlMjIlMjB2YWx1ZSUzRCUyMiUyMiUyMHJlcXVpcmVkJTNFJTNDJTJGZGl2JTNFJTBBJTNDZGl2JTIwY2xhc3MlM0QlMjJ0bnAtZmllbGQlMjB0bnAtcHJpdmFjeS1maWVsZCUyMiUzRSUzQ2xhYmVsJTNFJTNDaW5wdXQlMjB0eXBlJTNEJTIyY2hlY2tib3glMjIlMjBuYW1lJTNEJTIybnklMjIlMjByZXF1aXJlZCUyMGNsYXNzJTNEJTIydG5wLXByaXZhY3klMjIlM0UlQzIlQTBCeSUyMGNvbnRpbnVpbmclMkMlMjB5b3UlMjBhY2NlcHQlMjB0aGUlMjBwcml2YWN5JTIwcG9saWN5JTNDJTJGbGFiZWwlM0UlM0MlMkZkaXYlM0UlM0NkaXYlMjBjbGFzcyUzRCUyMnRucC1maWVsZCUyMHRucC1maWVsZC1idXR0b24lMjIlM0UlM0NpbnB1dCUyMGNsYXNzJTNEJTIydG5wLXN1Ym1pdCUyMiUyMHR5cGUlM0QlMjJzdWJtaXQlMjIlMjB2YWx1ZSUzRCUyMlN1YnNjcmliZSUyMiUyMCUzRSUwQSUzQyUyRmRpdiUzRSUwQSUzQyUyRmZvcm0lM0UlMEElM0MlMkZkaXYlM0UlM0NiciUyRiUzRSUzQyUyRnAlM0U=[/vc_raw_html][/vc_column][/vc_row]
No Result
View All Result
  • Contact Us
  • Homepages
  • Business
  • Guide

© 2024 APPROX FOUNDATION - The Crypto Currency News