Author

Topic: [BOUNTY 0.01BTC] Integer to Private key. How to generate in sequence? (Read 3548 times)

full member
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
http://stackoverflow.com/questions/22293864/ruby-openssl-convert-elliptic-curve-point-octet-string-into-opensslpkeyec

Code:
key =  '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
Code:
point.to_bn.to_s
but that is not enough to generate an address
full member
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
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
full member
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
Do you understand how could I change the function
Code:
curve.generator.multiply_by_scalar(record)
from the ECDSA gem

by 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
full member
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
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!
    
Code:
uncompressed = "\x04" + [pub_key.x.to_hexa].pack("H*") + [pub_key.y.to_hexa].pack("H*")
legendary
Activity: 3472
Merit: 4801
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.
legendary
Activity: 3472
Merit: 4801
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).
staff
Activity: 3458
Merit: 6793
Just writing some code
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.
full member
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
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
staff
Activity: 3458
Merit: 6793
Just writing some code
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.
full member
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
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/


Code:
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 Smiley

But now the second part of generating the address is where I'm struggling

Code:

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
legendary
Activity: 1042
Merit: 2805
Bitcoin and C♯ Enthusiast
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)
legendary
Activity: 3472
Merit: 4801
-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_format

The 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

staff
Activity: 3458
Merit: 6793
Just writing some code
That worked perfectly, thank you Grin


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.
full member
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
That worked perfectly, thank you Grin


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.
staff
Activity: 3458
Merit: 6793
Just writing some code
Then you perform sha256d on it (two rounds of sha256 hashing) and you get
Code:
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.
full member
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
Then you perform sha256d on it (two rounds of sha256 hashing) and you get
Code:
a85aa87e9879f34d1449e35c58e64d9325733ca2efb4577e6720ec42c3625783

What is happening?

=> string = '0x800000000000000000000000000000000000000000000000000000000000000001'
=> 2.times { string = Digest::SHA256.hexdigest(string) }

irb(main):284:0> c3d128a531b3ee00caef9cbaa2fe69e1fc94de99aaa6400c73147fac147cd58e
full member
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
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_encoding

First, you have to take your private key in hex form and concatenate it with the WIF version byte, which is 0x80. You will get

Code:
0x800000000000000000000000000000000000000000000000000000000000000001

Then you perform sha256d on it (two rounds of sha256 hashing) and you get
Code:
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
Code:
0x800000000000000000000000000000000000000000000000000000000000000001a85aa87e

Lastly you convert it from hex format to Base 58 and you get
Code:
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 Wink
staff
Activity: 3458
Merit: 6793
Just writing some code
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_encoding

First, you have to take your private key in hex form and concatenate it with the WIF version byte, which is 0x80. You will get

Code:
0x800000000000000000000000000000000000000000000000000000000000000001

Then you perform sha256d on it (two rounds of sha256 hashing) and you get
Code:
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
Code:
0x800000000000000000000000000000000000000000000000000000000000000001a85aa87e

Lastly you convert it from hex format to Base 58 and you get
Code:
5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf

That is the Wallet Import Format of the private key 1.
full member
Activity: 211
Merit: 100
1ACEGiLZnZoG7KUNkMwAT8tBuJ6jsrwj5Q
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.html
http://directory.io
I 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/PrivateKey

Please clarify what am I missing.
Jump to: