Bitcoin Forum
April 27, 2024, 03:11:01 PM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: pubkey decompression  (Read 241 times)
RBan (OP)
Newbie
*
Offline Offline

Activity: 12
Merit: 10


View Profile
July 22, 2020, 06:36:10 PM
 #1

Anyone know how to modify this code so that it converts the input public key into a compressed P2PKH address instead of uncompressed ?

Code:
def public_key_to_address(public_key):
    #print('Wanting to [%s] this to address'%public_key)
    output = []; alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
    var = hashlib.new('ripemd160')
    try:
        var.update(hashlib.sha256(binascii.unhexlify(public_key.encode())).digest())
        var = '00' + var.hexdigest() + hashlib.sha256(hashlib.sha256(binascii.unhexlify(('00' + var.hexdigest()).encode())).digest()).hexdigest()[0:8]
        count = [char != '0' for char in var].index(True) // 2
        n = int(var, 16)
        while n > 0:
            n, remainder = divmod(n, 58)
            output.append(alphabet[remainder])
        for i in range(count): output.append(alphabet[0])
        return ''.join(output[::-1])
    except:
        # Nothing
        return -1
1714230661
Hero Member
*
Offline Offline

Posts: 1714230661

View Profile Personal Message (Offline)

Ignore
1714230661
Reply with quote  #2

1714230661
Report to moderator
1714230661
Hero Member
*
Offline Offline

Posts: 1714230661

View Profile Personal Message (Offline)

Ignore
1714230661
Reply with quote  #2

1714230661
Report to moderator
The Bitcoin network protocol was designed to be extremely flexible. It can be used to create timed transactions, escrow transactions, multi-signature transactions, etc. The current features of the client only hint at what will be possible in the future.
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
1714230661
Hero Member
*
Offline Offline

Posts: 1714230661

View Profile Personal Message (Offline)

Ignore
1714230661
Reply with quote  #2

1714230661
Report to moderator
1714230661
Hero Member
*
Offline Offline

Posts: 1714230661

View Profile Personal Message (Offline)

Ignore
1714230661
Reply with quote  #2

1714230661
Report to moderator
1714230661
Hero Member
*
Offline Offline

Posts: 1714230661

View Profile Personal Message (Offline)

Ignore
1714230661
Reply with quote  #2

1714230661
Report to moderator
TheArchaeologist
Sr. Member
****
Offline Offline

Activity: 310
Merit: 727


---------> 1231006505


View Profile WWW
July 23, 2020, 08:56:56 AM
Last edit: July 23, 2020, 04:09:59 PM by TheArchaeologist
Merited by El duderino_ (4), pooya87 (1), ABCbits (1), Heisenberg_Hunter (1)
 #2

Anyone know how to modify this code so that it converts the input public key into a compressed P2PKH address instead of uncompressed ?
You don't need to change any code in that function. You pass a compressed public key as parameter to the function and you get the P2PKH-address for the compressed key. Or you pass an uncompressed public key and get the P2PKH-address returned for the uncompressed address. There is no difference between the two in the steps from public key to the base-58 encoded address.

Code:
#example for uncompressed
pubkey = '041A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7ACCF8E941F95AE80B8F373229B7A3F83144160D8982E648F60C8E5CB968EC72E'
print(public_key_to_address(pubkey))

Results in:
Wanting to [041A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7ACCF8E941F95AE80B8F373229B7A3F83144160D8982E648F60C8E5CB968EC72E] this to address
1BoatSLRHtKNngkdXEeobR76b53LETtpyT

#example for compressed
pubkey = '021A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7'
print(public_key_to_address(pubkey))

Results in:
Wanting to [021A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7] this to address
1AYNNMBpXwV7kVveDmFALhCU8VTA3yTs88

Sooner or later you're going to realize, just as I did, that there's a difference between knowing the path and walking the path
HCP
Legendary
*
Offline Offline

Activity: 2086
Merit: 4316

<insert witty quote here>


View Profile
July 30, 2020, 12:20:01 AM
Merited by ABCbits (1), Heisenberg_Hunter (1), math09183 (1)
 #3

If you're just trying to convert ONE uncompressed pubkey to compressed (or vice versa)... you can use this: https://iancoleman.io/bitcoin-key-compression/

If you want to do it in code, then the algorithm is:

Code:
1. Starting with uncompressed Pubkey, drop the "04" prefix
041A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7ACCF8E941F95AE80B8F373229B7A3F83144160D8982E648F60C8E5CB968EC72E
--> 1A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7ACCF8E941F95AE80B8F373229B7A3F83144160D8982E648F60C8E5CB968EC72E

2. Split into X (1st 32 bytes) and Y (2nd 32 bytes)
1A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7ACCF8E941F95AE80B8F373229B7A3F83144160D8982E648F60C8E5CB968EC72E
X -> 1A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7
Y -> ACCF8E941F95AE80B8F373229B7A3F83144160D8982E648F60C8E5CB968EC72E

3. Determine if Y is "Even" or "Odd"

If Y = even, then compressed prefix = 02
If Y = odd, then compressed prefix = 03

ACCF8E941F95AE80B8F373229B7A3F83144160D8982E648F60C8E5CB968EC72E is an "Even" number, so Compressed Prefix = 02

4. "Compressed" Public Key = Compressed Prefix + X

Compressed Prefix == 02
X == 1A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7
Compressed Pubkey -> 021A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7

█████████████████████████
████▐██▄█████████████████
████▐██████▄▄▄███████████
████▐████▄█████▄▄████████
████▐█████▀▀▀▀▀███▄██████
████▐███▀████████████████
████▐█████████▄█████▌████
████▐██▌█████▀██████▌████
████▐██████████▀████▌████
█████▀███▄█████▄███▀█████
███████▀█████████▀███████
██████████▀███▀██████████
█████████████████████████
.
BC.GAME
▄▄░░░▄▀▀▄████████
▄▄▄
██████████████
█████░░▄▄▄▄████████
▄▄▄▄▄▄▄▄▄██▄██████▄▄▄▄████
▄███▄█▄▄██████████▄████▄████
███████████████████████████▀███
▀████▄██▄██▄░░░░▄████████████
▀▀▀█████▄▄▄███████████▀██
███████████████████▀██
███████████████████▄██
▄███████████████████▄██
█████████████████████▀██
██████████████████████▄
.
..CASINO....SPORTS....RACING..
█░░░░░░█░░░░░░█
▀███▀░░▀███▀░░▀███▀
▀░▀░░░░▀░▀░░░░▀░▀
░░░░░░░░░░░░
▀██████████
░░░░░███░░░░
░░█░░░███▄█░░░
░░██▌░░███░▀░░██▌
░█░██░░███░░░█░██
░█▀▀▀█▌░███░░█▀▀▀█▌
▄█▄░░░██▄███▄█▄░░▄██▄
▄███▄
░░░░▀██▄▀


▄▄████▄▄
▄███▀▀███▄
██████████
▀███▄░▄██▀
▄▄████▄▄░▀█▀▄██▀▄▄████▄▄
▄███▀▀▀████▄▄██▀▄███▀▀███▄
███████▄▄▀▀████▄▄▀▀███████
▀███▄▄███▀░░░▀▀████▄▄▄███▀
▀▀████▀▀████████▀▀████▀▀
DougM
Full Member
***
Offline Offline

Activity: 173
Merit: 120


View Profile
July 30, 2020, 06:56:54 PM
 #4

If you're just trying to convert ONE uncompressed pubkey to compressed (or vice versa)... you can use this: https://iancoleman.io/bitcoin-key-compression/
Good site! thanks HCP.  RBan, I am not 100% sure what you are trying to do in the end, but I have a potentially similar thread going that you might want check out:
how do I extract the address from the output scriptPubKey for early coinbse tx?
HCP
Legendary
*
Offline Offline

Activity: 2086
Merit: 4316

<insert witty quote here>


View Profile
July 30, 2020, 10:13:45 PM
Merited by Heisenberg_Hunter (1)
 #5

I got bored and started playing around with this... So, here is my pretty crappy 5 minute Python code that will take any form of the PubKey (compressed/uncompressed) and output the address of the compressed public key.

NOTE: The hexstring -> int conversion for "y" should be both Python 2.7 and Python 3 "safe"... If you're using Python 3 there is the int.from_bytes() function available, which is a bit tidier.

Code: (pubkey_fun.py)
import binascii
import hashlib
import codecs

def public_key_to_address(public_key):
    print('Wanting to convert this [%s] to address'%public_key)
    output = []; alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
    var = hashlib.new('ripemd160')
    if public_key[0:2] == "04":
        print("------------------------")
        print("Found UNcompressed PubKey, converting")

        #break into x and y components
        x = public_key[2:66]
        y = public_key[66:]
        #print('x: ' + x)
        #print('y: ' + y)

        #convert hex str to int
        y = int(codecs.encode(binascii.unhexlify(y),'hex'),16)

        #test if y is "odd" or "even" and assign prefix as appropriate
        if 1 == (y % 2):
            public_key = "03" + x
        else:
            public_key = "02" + x

        print("Compressed PubKey: " + public_key)
        print("------------------------")
    try:
        var.update(hashlib.sha256(binascii.unhexlify(public_key.encode())).digest())
        var = '00' + var.hexdigest() + hashlib.sha256(hashlib.sha256(binascii.unhexlify(('00' + var.hexdigest()).encode())).digest()).hexdigest()[0:8]
        count = [char != '0' for char in var].index(True) // 2
        n = int(var, 16)
        while n > 0:
            n, remainder = divmod(n, 58)
            output.append(alphabet[remainder])
        for i in range(count): output.append(alphabet[0])
        return ''.join(output[::-1])
    except:
        # Nothing
        return -1

pubkey = '041A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7ACCF8E941F95AE80B8F373229B7A3F83144160D8982E648F60C8E5CB968EC72E'
print("CompressedAddress: " + public_key_to_address(pubkey) + "\n\n")

pubkey = '0408FD4E4E01356F3F0052E35FA186E54F736B209C025DFC5686FF98FF9A367A52520FAC06060EC7B3FEAE3F92EB840399B09E7E82AB332060D882ED4D4829D383'
print("CompressedAddress: " + public_key_to_address(pubkey) + "\n\n")

pubkey = '021A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7'
print("CompressedAddress: " + public_key_to_address(pubkey) + "\n\n")

hardcorepawn@HardCorePC:~$ vi pubkey_fun.py
hardcorepawn@HardCorePC:~$ python pubkey_fun.py
Wanting to convert this [041A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7ACCF8E941F95AE80B8F373229B7A3F83144160D8982E648F60C8E5CB968EC72E] to address
------------------------
Found UNcompressed PubKey, converting
Compressed PubKey: 021A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7
------------------------
CompressedAddress: 1AYNNMBpXwV7kVveDmFALhCU8VTA3yTs88


Wanting to convert this [0408FD4E4E01356F3F0052E35FA186E54F736B209C025DFC5686FF98FF9A367A52520FAC06060EC7B3FEAE3F92EB840399B09E7E82AB332060D882ED4D4829D383] to address
------------------------
Found UNcompressed PubKey, converting
Compressed PubKey: 0308FD4E4E01356F3F0052E35FA186E54F736B209C025DFC5686FF98FF9A367A52
------------------------
CompressedAddress: 1NCasbMhu3gUjmN6nNmrX3Kqb2H6bzY6Lw


Wanting to convert this [021A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7] to address
CompressedAddress: 1AYNNMBpXwV7kVveDmFALhCU8VTA3yTs88


hardcorepawn@HardCorePC:~$ vi pubkey_fun.py
hardcorepawn@HardCorePC:~$ python pubkey_fun.py
Even Y uncompressed PubKey
Wanting to convert this [041A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7ACCF8E941F95AE80B8F373229B7A3F83144160D8982E648F60C8E5CB968EC72E] to address
------------------------
Found UNcompressed PubKey, converting
Compressed PubKey: 021A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7
------------------------
CompressedAddress: 1AYNNMBpXwV7kVveDmFALhCU8VTA3yTs88


Odd Y uncompressed PubKey
Wanting to convert this [0408FD4E4E01356F3F0052E35FA186E54F736B209C025DFC5686FF98FF9A367A52520FAC06060EC7B3FEAE3F92EB840399B09E7E82AB332060D882ED4D4829D383] to address
------------------------
Found UNcompressed PubKey, converting
Compressed PubKey: 0308FD4E4E01356F3F0052E35FA186E54F736B209C025DFC5686FF98FF9A367A52
------------------------
CompressedAddress: 1NCasbMhu3gUjmN6nNmrX3Kqb2H6bzY6Lw


Compressed PubKey
Wanting to convert this [021A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7] to address
CompressedAddress: 1AYNNMBpXwV7kVveDmFALhCU8VTA3yTs88


hardcorepawn@HardCorePC:~$ cat pubkey_fun.py
import binascii
import hashlib
import codecs

def public_key_to_address(public_key):
    print('Wanting to convert this [%s] to address'%public_key)
    output = []; alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
    var = hashlib.new('ripemd160')
    if public_key[0:2] == "04":
        print("------------------------")
        print("Found UNcompressed PubKey, converting")

        #break into x and y components
        x = public_key[2:66]
        y = public_key[66:]
        #print('x: ' + x)
        #print('y: ' + y)

        #convert hex str to int
        y = int(codecs.encode(binascii.unhexlify(y),'hex'),16)

        #test if y is "odd" or "even" and assign prefix as appropriate
        if (y % 2) == 1:
            public_key = "03" + x
        else:
            public_key = "02" + x

        print("Compressed PubKey: " + public_key)
        print("------------------------")
    try:
        var.update(hashlib.sha256(binascii.unhexlify(public_key.encode())).digest())
        var = '00' + var.hexdigest() + hashlib.sha256(hashlib.sha256(binascii.unhexlify(('00' + var.hexdigest()).encode())).digest()).hexdigest()[0:8]
        count = [char != '0' for char in var].index(True) // 2
        n = int(var, 16)
        while n > 0:
            n, remainder = divmod(n, 58)
            output.append(alphabet[remainder])
        for i in range(count): output.append(alphabet[0])
        return ''.join(output[::-1])
    except:
        # Nothing
        return -1

pubkey = '041A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7ACCF8E941F95AE80B8F373229B7A3F83144160D8982E648F60C8E5CB968EC72E'
print("Even Y uncompressed PubKey:")
print("CompressedAddress: " + public_key_to_address(pubkey) + "\n\n")

pubkey = '0408FD4E4E01356F3F0052E35FA186E54F736B209C025DFC5686FF98FF9A367A52520FAC06060EC7B3FEAE3F92EB840399B09E7E82AB332060D882ED4D4829D383'
print("Odd Y uncompressed PubKey:")
print("CompressedAddress: " + public_key_to_address(pubkey) + "\n\n")

pubkey = '021A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7'
print("Compressed PubKey:")
print("CompressedAddress: " + public_key_to_address(pubkey) + "\n\n")



Output should be:
Code:
Even Y uncompressed PubKey:
Wanting to convert this [041A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7ACCF8E941F95AE80B8F373229B7A3F83144160D8982E648F60C8E5CB968EC72E] to address
------------------------
Found UNcompressed PubKey, converting
Compressed PubKey: 021A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7
------------------------
CompressedAddress: 1AYNNMBpXwV7kVveDmFALhCU8VTA3yTs88


Odd Y uncompressed PubKey:
Wanting to convert this [0408FD4E4E01356F3F0052E35FA186E54F736B209C025DFC5686FF98FF9A367A52520FAC06060EC7B3FEAE3F92EB840399B09E7E82AB332060D882ED4D4829D383] to address
------------------------
Found UNcompressed PubKey, converting
Compressed PubKey: 0308FD4E4E01356F3F0052E35FA186E54F736B209C025DFC5686FF98FF9A367A52
------------------------
CompressedAddress: 1NCasbMhu3gUjmN6nNmrX3Kqb2H6bzY6Lw


Compressed PubKey:
Wanting to convert this [021A87E4688D8B9445B5B038CB3B34C186331F1AB4FC0822DCCA44192043EAB3B7] to address
CompressedAddress: 1AYNNMBpXwV7kVveDmFALhCU8VTA3yTs88



█████████████████████████
████▐██▄█████████████████
████▐██████▄▄▄███████████
████▐████▄█████▄▄████████
████▐█████▀▀▀▀▀███▄██████
████▐███▀████████████████
████▐█████████▄█████▌████
████▐██▌█████▀██████▌████
████▐██████████▀████▌████
█████▀███▄█████▄███▀█████
███████▀█████████▀███████
██████████▀███▀██████████
█████████████████████████
.
BC.GAME
▄▄░░░▄▀▀▄████████
▄▄▄
██████████████
█████░░▄▄▄▄████████
▄▄▄▄▄▄▄▄▄██▄██████▄▄▄▄████
▄███▄█▄▄██████████▄████▄████
███████████████████████████▀███
▀████▄██▄██▄░░░░▄████████████
▀▀▀█████▄▄▄███████████▀██
███████████████████▀██
███████████████████▄██
▄███████████████████▄██
█████████████████████▀██
██████████████████████▄
.
..CASINO....SPORTS....RACING..
█░░░░░░█░░░░░░█
▀███▀░░▀███▀░░▀███▀
▀░▀░░░░▀░▀░░░░▀░▀
░░░░░░░░░░░░
▀██████████
░░░░░███░░░░
░░█░░░███▄█░░░
░░██▌░░███░▀░░██▌
░█░██░░███░░░█░██
░█▀▀▀█▌░███░░█▀▀▀█▌
▄█▄░░░██▄███▄█▄░░▄██▄
▄███▄
░░░░▀██▄▀


▄▄████▄▄
▄███▀▀███▄
██████████
▀███▄░▄██▀
▄▄████▄▄░▀█▀▄██▀▄▄████▄▄
▄███▀▀▀████▄▄██▀▄███▀▀███▄
███████▄▄▀▀████▄▄▀▀███████
▀███▄▄███▀░░░▀▀████▄▄▄███▀
▀▀████▀▀████████▀▀████▀▀
DarkDays
Legendary
*
Offline Offline

Activity: 2030
Merit: 1189


View Profile
August 13, 2020, 07:37:57 PM
 #6

Here's a quote from an old thread that you might find useful.

Hi,
I'd like to know if there is a formula to calculate the two possible values of Y from X
I use a library that needs them, and I don't really want to modify it
Actually it's very simple.

y2 = x3+ ax2 + b
so we need to perform square root to recover y from x. And it turns out that
sqrt(a) = a(q+1)/4

Now you just have to pick either the positive or negative solution. If the y that you calculated is even, and the first byte of the key is even, then use this value, otherwise, use the negative value which is q-y.

EDIT: relevant code I wrote as a patch for bitaddress.org
Code:
        
ec.CurveFp.prototype.decompressPoint = function(yOdd, X) {
    if(this.q.mod(BigInteger.valueOf(4)).equals(BigInteger.valueOf(3))) {
        // y^2 = x^3 + ax^2 + b, so we need to perform sqrt to recover y
        var ySquared = X.multiply(X.square().add(this.a)).add(this.b);

        // sqrt(a) = a^((q+1)/4) if q = 3 mod 4
        var Y = ySquared.x.modPow(this.q.add(BigInteger.ONE).divide(BigInteger.valueOf(4)), this.q);

        if(Y.testBit(0) !== yOdd) {
            Y = this.q.subtract(Y);
        }

        return new ec.PointFp(this, X, this.fromBigInteger(Y));
    }
    else {
        // only implement sqrt for q = 3 mod 4
        return null;
    }
};

// for now, work with hex strings because they're easier in JS
ec.CurveFp.prototype.decodePointHex = function (s) {
    switch (parseInt(s.substr(0, 2), 16)) { // first byte
    case 0:
        return this.infinity;
    case 2:
        return this.decompressPoint(false, this.fromBigInteger(new BigInteger(s.substr(2), 16)));
    case 3:
        return this.decompressPoint(true, this.fromBigInteger(new BigInteger(s.substr(2), 16)));
    case 4:
    case 6:
    case 7:
        var len = (s.length - 2) / 2;
        var xHex = s.substr(2, len);
        var yHex = s.substr(len + 2, len);

        return new ec.PointFp(this,
                              this.fromBigInteger(new BigInteger(xHex, 16)),
                              this.fromBigInteger(new BigInteger(yHex, 16)));

    default: // unsupported
        return null;
    }
};

Link is at : https://bitcointalk.org/index.php?topic=162805


Similar topics can be found being discussed at these links:
https://bitcoin.stackexchange.com/questions/86234/how-to-uncompress-a-public-key
https://gist.github.com/afk11/a3f1174f30e1e8d9ed2d

I hope these helped.
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!