Title: deriving chaincode from root privkey Post by: inf on September 18, 2014, 08:37:03 PM hi,
i have a problem with deriving the chaincode from the root key in my own code, i tried different private keys differently in c, php and python and i always get the same digest, but that digest does not fit the provided chaincode in the wallet generated by armory which i am checking against. as far as i understand, i simply get it like that: Code: hmac_sha256( key=sha256(sha256(ROOTKEY)) , ascii_message="Derive Chaincode from Root Key") basically, i can treat the message the same as hex Code: 0x44657269766520436861696E636F64652066726F6D20526F6F74204B6579 right? however, i tried it both as char * and uint8_t *. let my example be: Code: ROOTKEY = 0xC263A3ED1351B0E07D57B788688C3BD8EA0DE54788739093880AAEC2DFF21BCF all my sample programs, including the following python-script (sry, i really suck at python), deliver me Code: chaincode = 0x52c4ec3cd49b4af3c944f498e8d08fce2f3c432687408577ff6ae307d9ef1e6f while the wallet file says the actual chaincode is Code: chaincode_wallet = 0x90CED6C81A642182660C91A0418CDAF1165AE311378A3862723AED81D48A767E can someone please elaborate what i am getting wrong? thanks :) inf python code: Code: #!/usr/local/bin/python2.7 edit: i am using armory 0.92.1, generating wallets version 1.35. Title: Re: deriving chaincode from root privkey Post by: etotheipi on September 18, 2014, 08:56:37 PM I just ran the same calculation using armoryengine and got the chaincode you were expecting:
Code: >>> from armoryengine.ALL import * Usually these kinds of issues are endianness related. For instance, the first line k=hex_to_binary(...) interprets the strings as little-endian. You have to explicitly pass in a second arg with BIGENDIAN if you want to interpret it that way. When I first started learning Bitcoin, a significant amount of time was spent guessing and checking endianness switches for calculations with known outputs. That might be what you have to do here. Title: Re: deriving chaincode from root privkey Post by: btchris on September 19, 2014, 03:50:19 PM inf,
I think you've uncovered a bug in Armory's HMAC implementation. I very well could be (and in fact I hope I'm) wrong though.... In particular, this doesn't produce what I'd expect: Code: import hmac, hashlib Here's the definition of HMAC256 in ArmoryUtils.py: Code: def sha256(bits): I believe the problem is that this HMAC function takes and uses the hash size as a parameter (256 bits for SHA256), but it should be taking and using the block size instead (512 bits for SHA256). Could someone verify this, or hopefully correct me? Title: Re: deriving chaincode from root privkey Post by: etotheipi on September 19, 2014, 04:19:54 PM Wow! You're absolutely right. I have no idea how that got by me. I just tested it against a test vectors and found that the default hash sizes are half what they are supposed to be. I even remember looking up test vectors at the time... but I guess I didn't apply them? I guess the other factor is that that code has never had to interoperate with anything else expecting the same HMACs. Otherwise we would've noticed.
Well, we'll have to mark those functions as "special" (and keep using them for the old wallets), then update the parameters properly. The new wallets actually use HMAC from the Crypto++, and already pass all the test vectors. If I had tried doing CKD function with the python HMAC, I would have noticed. From RFC4231: Code: 4.2. Test Case 1 Title: Re: deriving chaincode from root privkey Post by: inf on September 19, 2014, 04:34:21 PM haha, i just spent 2 hours of debugging and came here to post that i can reproduce armorys chaincode when using SHA256_DIGEST_LENGTH instead of SHA256_BLOCK_LENGTH for the buffers in my HMAC implementation, just to read the same observation was made already! damnit :D
well, i will take that flaw into account for now :) thanks to both of you for your quick replies! |