acegilz (OP)
Full Member
Offline
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
|
|
December 15, 2016, 01:58:02 AM Last edit: December 16, 2016, 01:33:08 PM by acegilz |
|
I am struggling to understand why the first bitcoin address generating via private key is 1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm. Example mentions: https://www.palkeo.com/code/stealing-bitcoin.htmlhttp://directory.ioI assume they call it the first address because its private key may be the first that comes out when we are start encrypting from an optic of our standard decimal system, and starting on 1 or maybe 0. What is confusing me is that if I encrypt "1" with sha256 I get the key "c555eab45d08845ae9f10d452a99bfcb06f74a50b988fe7e48dd323789b88ee3" and that key when converting to WIF format is not the same private key as above. http://gobittest.appspot.com/PrivateKeyPlease clarify what am I missing.
|
|
|
|
achow101
Moderator
Legendary
Offline
Activity: 3542
Merit: 6886
Just writing some code
|
|
December 15, 2016, 02:26:31 AM |
|
First of all, Sha256 is a hash function, not an encryption method. They are two very different things. Secondly, the private keys do not translate directly to addresses, you have to do the encoding with the public keys after you derive them from the private key. You are doing it completely and absolutely incorrectly. The process you are trying to do is called Base 58 Check Encoding. The full description is here: https://en.bitcoin.it/wiki/Base58Check_encodingFirst, you have to take your private key in hex form and concatenate it with the WIF version byte, which is 0x80. You will get 0x800000000000000000000000000000000000000000000000000000000000000001 Then you perform sha256d on it (two rounds of sha256 hashing) and you get a85aa87e9879f34d1449e35c58e64d9325733ca2efb4577e6720ec42c3625783 Note the hashing is done on the bytes represented by the hex, not the ascii characters of the hex itself. Then you take the first 4 bytes of this hash and concatenate it to the end of the original hex string, so you get 0x800000000000000000000000000000000000000000000000000000000000000001a85aa87e Lastly you convert it from hex format to Base 58 and you get 5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf That is the Wallet Import Format of the private key 1.
|
|
|
|
acegilz (OP)
Full Member
Offline
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
|
|
December 15, 2016, 02:56:31 AM |
|
First of all, Sha256 is a hash function, not an encryption method. They are two very different things. Secondly, the private keys do not translate directly to addresses, you have to do the encoding with the public keys after you derive them from the private key. You are doing it completely and absolutely incorrectly. The process you are trying to do is called Base 58 Check Encoding. The full description is here: https://en.bitcoin.it/wiki/Base58Check_encodingFirst, you have to take your private key in hex form and concatenate it with the WIF version byte, which is 0x80. You will get 0x800000000000000000000000000000000000000000000000000000000000000001 Then you perform sha256d on it (two rounds of sha256 hashing) and you get a85aa87e9879f34d1449e35c58e64d9325733ca2efb4577e6720ec42c3625783 Note the hashing is done on the bytes represented by the hex, not the ascii characters of the hex itself. Then you take the first 4 bytes of this hash and concatenate it to the end of the original hex string, so you get 0x800000000000000000000000000000000000000000000000000000000000000001a85aa87e Lastly you convert it from hex format to Base 58 and you get 5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf That is the Wallet Import Format of the private key 1. Thank you for your patience in explaining step by step. I now understand how it works. Best Regards
|
|
|
|
acegilz (OP)
Full Member
Offline
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
|
|
December 15, 2016, 03:49:06 AM |
|
Then you perform sha256d on it (two rounds of sha256 hashing) and you get a85aa87e9879f34d1449e35c58e64d9325733ca2efb4577e6720ec42c3625783 What is happening? => string = '0x800000000000000000000000000000000000000000000000000000000000000001' => 2.times { string = Digest::SHA256.hexdigest(string) } irb(main):284:0> c3d128a531b3ee00caef9cbaa2fe69e1fc94de99aaa6400c73147fac147cd58e
|
|
|
|
achow101
Moderator
Legendary
Offline
Activity: 3542
Merit: 6886
Just writing some code
|
|
December 15, 2016, 03:54:20 AM |
|
Then you perform sha256d on it (two rounds of sha256 hashing) and you get a85aa87e9879f34d1449e35c58e64d9325733ca2efb4577e6720ec42c3625783 What is happening? => string = '0x800000000000000000000000000000000000000000000000000000000000000001' => 2.times { string = Digest::SHA256.hexdigest(string) } irb(main):284:0> c3d128a531b3ee00caef9cbaa2fe69e1fc94de99aaa6400c73147fac147cd58e It is not hashed as a string. That is hashed as raw hex bytes. Additionally, do not hash the 0x, that is not actually a byte, it is just an indicator that the string is a string representing the raw hex bytes of something.
|
|
|
|
acegilz (OP)
Full Member
Offline
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
|
|
December 15, 2016, 02:42:19 PM |
|
That worked perfectly, thank you What is the correct way of generating now valid addresses (both compressed and uncompressed) from these WIF's? It's strange how I can't find any information regarding this matter of creating private keys from integer and generate bitcoin addresses from WIF googling.
|
|
|
|
achow101
Moderator
Legendary
Offline
Activity: 3542
Merit: 6886
Just writing some code
|
|
December 15, 2016, 03:10:31 PM |
|
That worked perfectly, thank you What is the correct way of generating now valid addresses (both compressed and uncompressed) from these WIF's? It's strange how I can't find any information regarding this matter of creating private keys from integer and generate bitcoin addresses from WIF googling. You have to take your integer private key and perform the ECDSA public key derivation and get the corresponding public key. Then you hash that public key with Sha256 and then hash that hash with RIPEMD160. Then you perform Base 58 Check Encoding on the result in order to get an address.
|
|
|
|
DannyHamilton
Legendary
Offline
Activity: 3486
Merit: 4851
|
|
December 15, 2016, 04:50:45 PM |
|
-snip- It's strange how I can't find any information regarding this matter of creating private keys from integer -snip- from WIF googling.
Seriously? I just tried a Google search on "bitcoin wif". Here's THE TOP result, it has the exact steps listed by achow101. https://en.bitcoin.it/wiki/Wallet_import_formatThe VERY NEXT result explains that a private key is simply a 256 bit integer, and demonstrates that the integer can be represented in hexadecimal radix: https://en.bitcoin.it/wiki/Private_key
|
|
|
|
Coding Enthusiast
Legendary
Offline
Activity: 1043
Merit: 2818
Bitcoin and C♯ Enthusiast
|
|
December 15, 2016, 05:57:59 PM |
|
Just FYI in the link Danny gave this: 0C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D is your number (integer) but in another format (hex) and if you convert it to a number it is this number: 5500171714335001507730457227127633683517613019341760098818554179534751705629 (I used BigInteger Structure in .Net framework)
|
|
|
|
acegilz (OP)
Full Member
Offline
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
|
|
December 15, 2016, 07:51:06 PM Last edit: December 15, 2016, 08:35:18 PM by acegilz |
|
Ok, I have been trying to follow this ruby tutorial and trying to get the address #1 but it's not really being easy... http://royalforkblog.github.io/2014/07/31/address-gen/number = '800000000000000000000000000000000000000000000000000000000000000001' string = number bytes = [string].pack('H*') #this converts to hex bytes sha1 = Digest::SHA256.digest bytes sha2 = Digest::SHA256.hexdigest sha1
bytes= sha2[0...8] string = string+bytes
private_key = encode_base58(string) This is working But now the second part of generating the address is where I'm struggling curve = ECDSA::Group::Secp256k1 pub_key = curve.generator.multiply_by_scalar(sha1.to_bignum)
if pub_key.y % 2 == 0 # y is even leader = "\x02" else leader = "\x03" end pub_key_with_lead = leader + [pub_key.x.to_hexa].pack("H*")
pub_key_sha256 = Digest::SHA256.digest(pub_key_with_lead) pub_key_hash = Digest::RMD160.digest(pub_key_sha256)
pub_key_hash_and_version_and_checksum = cat_checksum("\x00" + pub_key_hash) pub_addr = pub_key_hash_and_version_and_checksum.to_base58
It generates bitcoin addresses that are not correct so I assume Im making something wrong, also I would like to know what changes I have to make to get the compressed and uncompressed addresses of the private key
|
|
|
|
achow101
Moderator
Legendary
Offline
Activity: 3542
Merit: 6886
Just writing some code
|
|
December 15, 2016, 08:12:57 PM |
|
What is that sha1 variable that you are getting the pubkey of? You should be getting the pubkey of the private key, which is 1.
|
|
|
|
acegilz (OP)
Full Member
Offline
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
|
|
December 15, 2016, 08:36:44 PM |
|
What is that sha1 variable that you are getting the pubkey of? You should be getting the pubkey of the private key, which is 1.
Yes, if you check the first code block its the hashing of the hex code of 80.........00001
|
|
|
|
achow101
Moderator
Legendary
Offline
Activity: 3542
Merit: 6886
Just writing some code
|
|
December 15, 2016, 08:51:56 PM |
|
What is that sha1 variable that you are getting the pubkey of? You should be getting the pubkey of the private key, which is 1.
Yes, if you check the first code block its the hashing of the hex code of 80.........00001 That hash IS NOT the private key. Your private key is just 1, nothing else. The 80 bye on front is not part of the private key. The hash is not the private key. Your private key is just 1.
|
|
|
|
DannyHamilton
Legendary
Offline
Activity: 3486
Merit: 4851
|
|
December 15, 2016, 09:00:05 PM |
|
What is that sha1 variable that you are getting the pubkey of? You should be getting the pubkey of the private key, which is 1.
Yes, if you check the first code block its the hashing of the hex code of 80.........00001 So, then you are NOT calculating the bitcoin address of private key 1 You are calculating the bitcoin address of private key 76148737704215984528336581924048280615126714225363445232814723661301765265283. (which is that value you get when you double hash 0x800000000000000000000000000000000000000000000000000000000000000001) The addresses you should get in that case would be: 1BajJZaEgv6AoHrm96Yb83gdPFqC2NhHJg (Compressed Address) 19xWR81nzzn4LRV8dnAzJ46ip6L2Co4Rpa (Uncompressed Address) If you want the bitcoin address of the private key 1, then you need to calculate curve.generator.multiply_by_scalar() on the value 1 (not the hash of 1).
|
|
|
|
DannyHamilton
Legendary
Offline
Activity: 3486
Merit: 4851
|
|
December 15, 2016, 09:18:26 PM |
|
It really sounds like you need to work on understanding some of the basics before you start trying to write code.
A bitcoin private key is just a random integer. Any integer between 1 and 115792089237316195423570985008687907852837564279074904382605163141518161494336 is a valid private key. Just pick a random integer, and you've got a private key. In the case of this thread, you've chosen the number 1.
Now, once you have your integer you can represent that integer in any preferred format.
For example, you could represent it as a 256 bit binary number: 0b00000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000001
Or you could represent it as a 64 digit hex number (representing the 32 bytes): 0x0000000000000000000000000000000000000000000000000000000000000001
Or you could represent it in Wallet Import Format (WIF): 5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf
No matter what representation you use, the end result is that the value of the actual private key is 1.
To calculate the public key, you need to multiply the base point "G" on the Secp256k1 curve by the VALUE of the private key (in this case, 1).
Then to get a bitcoin address, you need to SHA256 hash the public key, then RIPEMD160 hash the result of the SHA256 hash, then calculate the base58check representation of the the RIPEMD160 hash.
The hashing that achow101 explained to you at the top of this thread was for the purposes of computing a CHECKSUM. That's a value that is stored in the WIF that can be used to verify that the user didn't make a typing error while entering their private key. The 4 bytes from the hash (and first byte version number) need to be removed from the WIF representation before you try to calculate the public key.
|
|
|
|
acegilz (OP)
Full Member
Offline
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
|
|
December 16, 2016, 01:23:54 AM Last edit: December 16, 2016, 01:39:30 AM by acegilz |
|
Great! Thank you both for the detailed reply. Honestly I have been looking for replies like these everywhere without success, that's why I opened this. One last question, I could generate a compressed address, what changes or extras do I have to make to get the uncompressed address? Edit: Gotcha! uncompressed = "\x04" + [pub_key.x.to_hexa].pack("H*") + [pub_key.y.to_hexa].pack("H*")
|
|
|
|
acegilz (OP)
Full Member
Offline
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
|
|
December 16, 2016, 12:35:05 PM Last edit: December 16, 2016, 12:48:55 PM by acegilz |
|
Do you understand how could I change the function curve.generator.multiply_by_scalar(record) from the ECDSA gemby something provided by native openssl? The first solution takes 30 seconds to load 100 records (300ms each), I heard the openssl is pretty much faster but I don't find anything equivalent there(maybe there isn't..) If I understand correctly we are expanding the Ecurve n times ( the private key numbers) and then we use some coordinate (x or y dunno) based on the other coordinate (as reference) attributed with the value of n
|
|
|
|
acegilz (OP)
Full Member
Offline
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
|
|
December 16, 2016, 01:08:32 PM |
|
Bounty of BTC0.01 added for who could explain me how to put this working efficiently in ruby. It's urgent and I can't find it out by myself
|
|
|
|
Coding Enthusiast
Legendary
Offline
Activity: 1043
Merit: 2818
Bitcoin and C♯ Enthusiast
|
|
December 16, 2016, 03:52:11 PM |
|
|
|
|
|
acegilz (OP)
Full Member
Offline
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
|
|
December 17, 2016, 07:48:48 PM |
|
http://stackoverflow.com/questions/22293864/ruby-openssl-convert-elliptic-curve-point-octet-string-into-opensslpkeyeckey = '04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284' key_bn = OpenSSL::BN.new(key, 16) #Input: 16=Hexa, Output: BigNumber group = OpenSSL::PKey::EC::Group.new('secp256k1')
point = OpenSSL::PKey::EC::Point.new(group, key_bn) Is it possible to get the x and y coordinates individually from point? I think I can get the merged coordinates with but that is not enough to generate an address
|
|
|
|
|