Wednesday, July 10, 2024

The way to uncompress a public key?

Factors are decompressed by fixing for y within the equation used for secp256k1’s elliptic curve the place x is the final 32 bytes of your public key. The equation is y^2 = x^3 + 7. You’re going to get 2 potential y values, one even and one odd. The proper one is indicated by the prefix byte of your public key which signifies whether or not y is even or odd.

Be aware that every one operations have to be modulo p which is outlined by secp256k1’s spec as being 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F.

This python script will decompress the 2 public keys that you’ve posted:

#! /usr/bin/env python3

import binascii

p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F

def decompress_pubkey(pk):
    x = int.from_bytes(pk[1:33], byteorder="large")
    y_sq = (pow(x, 3, p) + 7) % p
    y = pow(y_sq, (p + 1) // 4, p)
    if y % 2 != pk[0] % 2:
        y = p - y
    y = y.to_bytes(32, byteorder="large")
    return b'x04' + pk[1:33] + y

print(binascii.hexlify(decompress_pubkey(binascii.unhexlify('0229b3e0919adc41a316aad4f41444d9bf3a9b639550f2aa735676ffff25ba3898'))).decode())
print(binascii.hexlify(decompress_pubkey(binascii.unhexlify('02f15446771c5c585dd25d8d62df5195b77799aa8eac2f2196c54b73ca05f72f27'))).decode())

The uncompressed public keys are:

0429b3e0919adc41a316aad4f41444d9bf3a9b639550f2aa735676ffff25ba3898d6881e81d2e0163348ff07b3a9a3968401572aa79c79e7edb522f41addc8e6ce
04f15446771c5c585dd25d8d62df5195b77799aa8eac2f2196c54b73ca05f72f274d335b71c85e064f80191e1f7e2437afa676a3e2a5a5fafcf0d27940cd33e4b4

Pubkey decompression is totally totally different and unrelated to deal with era. Addresses are generated by taking a public key as is (both compressed or uncompressed) hashing it, after which encoding it. The compression issues as a result of the ensuing serialized public will produce one hash (and thus one deal with) when it’s compressed, and a unique hash (and thus totally different deal with) when uncompressed.

Addresses are encoded by hashing the serialized public key with SHA256 after which with RIPEMD160. The ensuing hash is encoded utilizing Base58 Examine encoding.

Within the transaction you supplied, the three public keys:

04ad90e5b6bc86b3ec7fac2c5fbda7423fc8ef0d58df594c773fa05e2c281b2bfe877677c668bd13603944e34f4818ee03cadd81a88542b8b4d5431264180e2c28
0229b3e0919adc41a316aad4f41444d9bf3a9b639550f2aa735676ffff25ba3898
02f15446771c5c585dd25d8d62df5195b77799aa8eac2f2196c54b73ca05f72f27

have the next hashes respectively:

946cb2e08075bcbaf157e47bcb67eb2b2339d242
55af2ea3c45819c6c5ae710d29fcaaced5b00cc7
8b38a8d40e08362046dee55c1c94e7991d7dec75

Encoding these as model 0 addresses with Base 58 Examine encoding leads to the addresses you expect:

1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P
18p4JBHP3EAKCc4jqN8XzuEJtvq8G9NAot
1Dh8oSChJWZQx5sr7ePsBNtw7uKMsNnYNC

The code I used for that is:

#! /usr/bin/env python3

import binascii
import hashlib

b58_digits="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

def sha256(s):
    return hashlib.new('sha256', s).digest()

def ripemd160(s):
    return hashlib.new('ripemd160', s).digest()

def hash256(s):
    return sha256(sha256(s))

def hash160(s):
    return ripemd160(sha256(s))

def encode(b):
    # Convert big-endian bytes to integer
    n = int('0x0' + binascii.hexlify(b).decode('utf8'), 16)

    # Divide that integer into bas58
    res = []
    whereas n > 0:
        n, r = divmod (n, 58)
        res.append(b58_digits[r])
    res="".be part of(res[::-1])

    # Encode main zeros as base58 zeros
    import sys
    czero = b'x00'
    if sys.model > '3':
        # In Python3 indexing a bytes returns numbers, not characters.
        czero = 0
    pad = 0
    for c in b:
        if c == czero: pad += 1
        else: break
    return b58_digits[0] * pad + res

def to_address(b, model):
    knowledge = model + b
    checksum = hash256(knowledge)[0:4]
    knowledge += checksum
    return encode(knowledge)

pk1 = binascii.unhexlify("0229b3e0919adc41a316aad4f41444d9bf3a9b639550f2aa735676ffff25ba3898")
pk2 = binascii.unhexlify("02f15446771c5c585dd25d8d62df5195b77799aa8eac2f2196c54b73ca05f72f27")
pk3 = binascii.unhexlify("04ad90e5b6bc86b3ec7fac2c5fbda7423fc8ef0d58df594c773fa05e2c281b2bfe877677c668bd13603944e34f4818ee03cadd81a88542b8b4d5431264180e2c28")

h1 = hash160(pk1)
h2 = hash160(pk2)
h3 = hash160(pk3)

print(to_address(h3, b'x00'))
print(to_address(h1, b'x00'))
print(to_address(h2, b'x00'))

(Base58 encoding operate from https://github.com/bitcoin-core/HWI/blob/grasp/hwilib/base58.py)

As you may see, this doesn’t do any level compression or decompression. Relatively it takes the general public key as it’s and encodes it.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles