Author

Topic: Why does Bitcoin's SHA256 implementation work differently? (Read 811 times)

newbie
Activity: 5
Merit: 0
@achow101: Thanks for clarifying... I think I looked at too many bits yesterday. This helps a lot!

@DannyHamilton: Thanks as well for putting in the effort to color it and everything. However you did fake your comment a little bit:
You wrote:
Quote
- snip -
//14508459...57e74b
I wrote:
Quote
//14508459...057e74b
See the additional zero there? That kind of bothers me still... Another implementation contains the zeros as well, so I think there is a problem with my Java implementation... I'll investigate...

EDIT: Simple problem... my Java code was swallowing leading zeros...
Bad code:
Code:
System.out.format("%x", c);
Good code:
Code:
System.out.format("%02x", c);

Thanks again to all here for helping me with this problem!

EDIT2: So just for completness sake in case someone googles this... this Java function seems to produce the same thing as Bitcoin's Hash(...) function:
Code:
static byte[] btcSha256d(byte[] memory) throws NoSuchAlgorithmException{
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] result = md.digest(md.digest(memory));
for(int i=0;i byte temp = result[i];
result[i]=result[result.length-i-1];
result[result.length-i-1]=temp;
}
return result;
}
legendary
Activity: 1042
Merit: 2805
Bitcoin and C♯ Enthusiast
Bitcoin uses little endian byte order. This is not what you are doing.

Not always! There are cases which use Big-endian.
legendary
Activity: 3472
Merit: 4801
- snip -
This is my code:
Code:
- snip -
//14508459...57e74b

Here, let me color code that for you.  Perhaps it will be easier to see what achow101 is saying...
14508459...57e74b

- snip -
I thought maybe I have to double hash, but this leaves me with this:
Code:
- snip -
//4be757e8f70eb93640c8468274ba759745a7aa2b7d25ab1e421b259845014

Take a look at the matching colors, see if you can spot what has happened...
4be757e8f70eb93640c8468274ba759745a7aa2b7d25ab1e421b259845014
donator
Activity: 55
Merit: 3
the internet never sleeps
Bitcoin uses little endian byte order. This is not what you are doing.
staff
Activity: 3458
Merit: 6793
Just writing some code
Thanks for your reply, I still don't understand the problem though. The array consists of 80 bytes all being of value 0x00. This should be the same regardless of byte order, shouldn't it?

EDIT: I don't know really why, but I tested the byte order just to be sure... as expected it doesn't make a difference for the byte array in question.
It has nothing to do with what you initialized the array with nor with anything that you passed into the function. The endianness has to do with the output of the hash function. The output is different because Bitcoin uses little endian byte order for basically everything, so the output of the hash function will be in little endian byte order. However most other SHA256 implementations will output in big endian byte order so you will need to reverse the hash from other implementations in order to get the little endian byte order that Bitcoin uses.
newbie
Activity: 5
Merit: 0
Thanks for your reply, I still don't understand the problem though. The array consists of 80 bytes all being of value 0x00. This should be the same regardless of byte order, shouldn't it?

EDIT: I don't know really why, but I tested the byte order just to be sure... as expected it doesn't make a difference for the byte array in question.
staff
Activity: 3458
Merit: 6793
Just writing some code
The hashes that Bitcoin uses are double SHA256 hashes. The hashes are also usually in Little Endian byte order. So your second attempt with the double hash is actually correct, but with the wrong byte order. You need to byte swap your result to be in the right ordering.
newbie
Activity: 5
Merit: 0
Hi, I am new here, so if this is the wrong forum, please let me know where this post is better placed.

I was trying to write my own miner, but simply don't understand what the Hash() function in hash.h is doing.
This is my code:
Code:
// allocate 80 bytes of 0x00s
unsigned char* memory = (unsigned char*)malloc(80);
int* result = (unsigned int*)malloc(32);
memory,0,80);
memory,0,32);

seems to be doing hashes under the SHA-256 name
hash = Hash(memory, memory+80);
hash:%s\n",hash.GetHex().c_str());
//14508459...0e57e74b

However when I try to do this with _any_ other SHA256 implementation I always get a different result (I tried three, which gave me the same result). Here is my Java code:
Code:
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digest = md.digest(ByteBuffer.allocate(80).array());
for(byte c : digest) {
System.out.format("%x", c);
}
//5b6fb58e61fa475939767d68a446f97f1bff2c0e5935a3ea8bb51e6515783d8

I thought maybe I have to double hash, but this leaves me with this:
Code:
MessageDigest md2 = MessageDigest.getInstance("SHA-256");
byte[] digest2 = md2.digest(md2.digest(ByteBuffer.allocate(80).array()));
for(byte c : digest2) {
System.out.format("%x", c);
}
//4be757e8f70eb93640c8468274ba759745a7aa2b7d25ab1e421b259845014

So the hash I get from the Bitcoin implementation differs from any other SHA256 implementation for some reason... what am I missing? Am I using the algorithm wrong? Is it initialized differently (other implementation don't give me a possibility to parametrize the function)? Does it simply work differently (not according to the standard)?

Any help would be appreciated
Jump to: