• 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

HTX DAO Launches $10M Genesis Program to Propel the Crypto-AI Convergence and Advance Financial Freedom

HTX DAO Launches $10M Genesis Program to Propel the Crypto-AI Convergence and Advance Financial Freedom

September 3, 2026
SEC Sets 24-Hour Trading Roundtable As Markets Move Toward Always-On Finance

CFTC Issues Event Contract Guidance As Prediction Markets Face Scrutiny

September 3, 2026



Source link

Share76Tweet47

Related Posts

HTX DAO Launches $10M Genesis Program to Propel the Crypto-AI Convergence and Advance Financial Freedom

HTX DAO Launches $10M Genesis Program to Propel the Crypto-AI Convergence and Advance Financial Freedom

by Moussa
September 3, 2026
0

Trusted Editorial content, reviewed by leading industry experts and seasoned editors. Ad Disclosure Amid a pivotal reshaping of the global...

SEC Sets 24-Hour Trading Roundtable As Markets Move Toward Always-On Finance

CFTC Issues Event Contract Guidance As Prediction Markets Face Scrutiny

by Moussa
September 3, 2026
0

The CFTC has issued regulatory enforcement guidance for event contract derivatives, sharpening the lines around prediction markets at a time...

Remixpoint Goes All-In on Bitcoin After $5.54 Million Altcoin Sale

Remixpoint Goes All-In on Bitcoin After $5.54 Million Altcoin Sale

by Moussa
September 3, 2026
0

Key TakeawaysRemixpoint sold all ETH, SOL, XRP, and DOGE for $5.54M, booking about $743K in profit.The company now holds only...

Bitcoin Pi Cycle – top and bottom indicator – precise definition [closed]

by Moussa
September 3, 2026
0

From my reading I understand that: The Bitcoin Pi Cycle top indicator signals a top when: 111 day Simple Moving...

Sality Takedown Isolates 15,000 Machines Used in Crypto Theft

Sality Takedown Isolates 15,000 Machines Used in Crypto Theft

by Moussa
September 3, 2026
0

CrowdStrike and the U.S. Department of Justice disrupted the Sality botnet, isolating more than 15,000 infected machines that had been...

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