BitShares Forum

Main => Technical Support => Topic started by: 5chdn on December 31, 2013, 05:37:43 pm

Title: How to encode a PTS address?
Post by: 5chdn on December 31, 2013, 05:37:43 pm
Hi,

I've taken a raw asm public key string from a transaction and followed this guide (https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses) to convert it ot a base58 encoded PTS address. But the result does not start with P.... is there anything special about PTS addresses or did I just failed to encode correctly?

Cheers
don

PS, see also http://stackoverflow.com/q/20860641/1260906


The approach above was wrong. Can someone tell me step by step how I can convert the ASM Public Key Hash
Code: [Select]
028401a2e512b1b91b882ee1c9291cd407c10916bf791662f7189c9c805643e51c to a PTS Public Key Address?
Title: Re: How to encode a PTS address?
Post by: toast on January 02, 2014, 11:58:50 pm
Which part of this diagram does your string correspond to?

https://en.bitcoin.it/w/images/en/9/9b/PubKeyToAddr.png

You should be able to follow that diagram, except use 0x38 as the network byte.
Title: Re: How to encode a PTS address?
Post by: 5chdn on January 03, 2014, 08:52:06 am
Which part of this diagram does your string correspond to?

https://en.bitcoin.it/w/images/en/9/9b/PubKeyToAddr.png

You should be able to follow that diagram, except use 0x38 as the network byte.
Why 38? PTS should be 56?

The ASM hash is not in that diagram. It's difficult.

Look at this post http://bitcoin.stackexchange.com/a/8864/6441
He is doing what I need but I cant interpret his python code, he is showing it as example but not explaining what he is doing or why and where he got the information from...
Title: Re: How to encode a PTS address?
Post by: toast on January 03, 2014, 05:48:30 pm
0x38 == 56
Will check it out when I get to a computer
Title: Re: How to encode a PTS address?
Post by: 5chdn on January 03, 2014, 06:33:29 pm
0x38 == 56
Will check it out when I get to a computer

Yep sorry, of course!
Title: Re: How to encode a PTS address?
Post by: toast on January 03, 2014, 06:35:46 pm
I'm not sure what you mean by ASM hash. Let me step through the code for you, hopefully you can match up your string to some part of this process.

Code: [Select]
OP_DUP OP_HASH160 496650cdb4b6275ca4478c0ce98cb6f7224bb1e7 OP_EQUALVERIFY OP_CHECKSIG
The string in there is sha256(public_key). This script creates ripemd160(sha256(public_key)), then does some verification on it. The script outputs this string, which is <sig> <pubkey>.

Code: [Select]
304402205e81e8ed0b1f7cf6d1d415961859d3b95f5e5c353af303b6cef1e3efa6c3349702202fa9fdd6914abd0e9606c78899e7f3010cafdad211645cf459ae18b3b827b2c101 0365e0beb9a0c1497f3667067aeb8f3ea9dc4c9d5696cee7f19eae49f9457a5cfb
This is where the python code starts, assigning the string to the variable "script". I cut some unimportant stuff.

Code: [Select]
script = "304402205e81e8ed0b1f7cf6d1d415961859d3b95f5e5c353af303b6cef1e3efa6c3349702202fa9fdd6914abd0e9606c78899e7f3010cafdad211645cf459ae18b3b827b2c101 0365e0beb9a0c1497f3667067aeb8f3ea9dc4c9d5696cee7f19eae49f9457a5cfb".split()
h = hashlib.sha256(script[1].decode("hex")).digest()
ripe160 =  hashlib.new('ripemd160')
ripe160.update(h)
d = ripe160.digest()

This just takes the pubkey and assigns ripemd160(sha256(pubkey)) to the variable "d". The rest of the code is pretty easy to match up with the diagram I linked above.

Code: [Select]
#Prepend the Mainnet prefix
address = ('\x00' + d)
Replace 0x00 with 0x38.
Code: [Select]
#Calculate checksum
checksum = hashlib.sha256(hashlib.sha256(address).digest()).digest()[:4]
# Build the raw address
address += checksum
# Encode the address in base58
encoded_address = b58encode(address)
print encoded_address

Le me know if this helps. I may be able to be more helpful if you go back a few steps and explain where you got your original "ASM hash".
Title: Re: How to encode a PTS address?
Post by: toast on January 03, 2014, 06:38:49 pm
Hmm, I noticed he may be applying sha256 an extra time in there, since it's not possible for the script ouput to contain the actual pubkey if the input is sha256(pubkey).

Again, it might be easier if we just try this process from the very start. Are you just manually trying to generate PTS public keys? What's your goal?
Title: Re: How to encode a PTS address?
Post by: toast on January 03, 2014, 06:41:39 pm
This link may be helpful.
https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses
Title: Re: How to encode a PTS address?
Post by: bytemaster on January 03, 2014, 06:51:12 pm
Code: [Select]
namespace bts
{
   pts_address::pts_address()
   {
      memset( addr.data, 0, sizeof(addr.data) );
   }

   pts_address::pts_address( const std::string& base58str )
   {
      std::vector<char> v = fc::from_base58( fc::string(base58str) );
      if( v.size() )
         memcpy( addr.data, v.data(), std::min<size_t>( v.size(), sizeof(addr) ) );

      if( !is_valid() )
      {
         FC_THROW_EXCEPTION( exception, "invalid pts_address ${a}", ("a", base58str) );
      }
   }

   pts_address::pts_address( const fc::ecc::public_key& pub )
   {
       auto dat      = pub.serialize_ecc_point();
       auto sha2     = fc::sha256::hash(dat.data, sizeof(dat) );
       auto rep      = fc::ripemd160::hash((char*)&sha2,sizeof(sha2));
       addr.data[0]  = 56;
       memcpy( addr.data+1, (char*)&rep, sizeof(rep) );
       auto check    = fc::sha256::hash( addr.data, sizeof(rep)+1 );
       check = fc::sha256::hash(check); // double
       memcpy( addr.data+1+sizeof(rep), (char*)&check, 4 );
   }

   /**
    *  Checks the address to verify it has a
    *  valid checksum and prefix.
    */
   bool pts_address::is_valid()const
   {
       if( addr.data[0]  != 56 ) return false;
       auto check    = fc::sha256::hash( addr.data, sizeof(fc::ripemd160)+1 );
       check = fc::sha256::hash(check); // double
       return memcmp( addr.data+1+sizeof(fc::ripemd160), (char*)&check, 4 ) == 0;
   }

   pts_address::operator std::string()const
   {
        return fc::to_base58( addr.data, sizeof(addr) );
   }
}

bitshares/src/pts_address.cpp
Title: Re: How to encode a PTS address?
Post by: 5chdn on January 03, 2014, 06:55:38 pm
Le me know if this helps. I may be able to be more helpful if you go back a few steps and explain where you got your original "ASM hash".

This is the ASM hash in the code below:
Code: [Select]
script[1] = 0365e0beb9a0c1497f3667067aeb8f3ea9dc4c9d5696cee7f19eae49f9457a5cfb
And thats where I'm stuck.
This is where the python code starts, assigning the string to the variable "script". I cut some unimportant stuff.

Code: [Select]
script = "304402205e81e8ed0b1f7cf6d1d415961859d3b95f5e5c353af303b6cef1e3efa6c3349702202fa9fdd6914abd0e9606c78899e7f3010cafdad211645cf459ae18b3b827b2c101 0365e0beb9a0c1497f3667067aeb8f3ea9dc4c9d5696cee7f19eae49f9457a5cfb".split()
h = hashlib.sha256(script[1].decode("hex")).digest()
ripe160 =  hashlib.new('ripemd160')
ripe160.update(h)
d = ripe160.digest()

This just takes the pubkey and assigns ripemd160(sha256(pubkey)) to the variable "d". The rest of the code is pretty easy to match up with the diagram I linked above.

What is h exactly? I wasnt able to reproduce this.
Title: Re: How to encode a PTS address?
Post by: toast on January 03, 2014, 07:07:21 pm
Ok yeah that script seems wrong. Let me try.

Code: [Select]
asm_hash = "your_hash"
extended_hash = "34" + asm_hash
binary_extended_hash = extended_hash.decode("hex")
double_hash = hashlib.sha256(hashlib.sha256(binary_extended_hash))
checksum = double_hash[:3]    # first 4 bytes
binary_address = binary_extended_hash + checksum
pts_address = b58encode(binary_address)

You might have to insert some prints to see make sure I'm converting between strings, hex, and binary correctly, and adjust accordingly. If you put a print after every line and show us the output we can try to help debug.
Title: Re: How to encode a PTS address?
Post by: 5chdn on January 03, 2014, 09:04:38 pm
Ok yeah that script seems wrong. Let me try.

Code: [Select]
asm_hash = "your_hash"
extended_hash = "34" + asm_hash
binary_extended_hash = extended_hash.decode("hex")
double_hash = hashlib.sha256(hashlib.sha256(binary_extended_hash))
checksum = double_hash[:3]    # first 4 bytes
binary_address = binary_extended_hash + checksum
pts_address = b58encode(binary_address)

You might have to insert some prints to see make sure I'm converting between strings, hex, and binary correctly, and adjust accordingly. If you put a print after every line and show us the output we can try to help debug.

toast, i really appreciate your help, but the original script is exactly doing what i want. your modified script is encoding correctly the wrong hash.

Code: [Select]
# this is the <sig pupkey> asm hash
script = "304402205e81e8ed0b1f7cf6d1d415961859d3b95f5e5c353af303b6cef1e3efa6c3349702202fa9fdd6914abd0e9606c78899e7f3010cafdad211645cf459ae18b3b827b2c101 0365e0beb9a0c1497f3667067aeb8f3ea9dc4c9d5696cee7f19eae49f9457a5cfb".split()

# this is the extracted pubkey
pub_key = script[1]

# this is the binary pubkey? (why is it called 'decode'?)
binary_pub_key = pub_key.decode("hex")

# thats a sha256 performed on the binary pub key
h = hashlib.sha256(binary_pub_key).digest()

# thats generating a new ripemd160 hash, isnt it?
ripe160 = hashlib.new('ripemd160')

# no idea whats happening here?
ripe160.update(h)

# no idea whats happening here?!?
d = ripe160.digest()

# the d is what I want to get, from here I know!
Title: Re: How to encode a PTS address?
Post by: toast on January 03, 2014, 09:07:44 pm
http://docs.python.org/2/library/hashlib.html#hashlib.hash.update

In that case it looks like

Code: [Select]
ripe160 = hashlib.new('ripemd160')
ripe160.update(h)
d = ripe160.digest()

is just computing ripemd160(h), no?