Replying to Avatar Dr. Hax

OK, I think I should have time tomorrow to attempt to start writing a little demo web app that will use a nostr:npub17tyke9lkgxd98ruyeul6wt3pj3s9uxzgp9hxu5tsenjmweue6sqq4y3mgl to log in.

Technically, it will support any software that can export an xpub and then sign an arbitrary message with an associated key, but my test case is the #SeedSigner.

The idea is not limited to just logging into a website, of course. However, for simplicity, my demo will be limited to just that.

My hope is that I'll be feeling well enough to grind through to the point where if you scan the QR code with a phone and then enter the string (for xpub and signature), you'll be able to demonstrate the capability. Adding in JS code to scan a QR code will probably be saved for another day's work.

Making some progress on this. I can get from seed words to entropy to the master node without any trouble, but when I try to get a subkey for a path, it doesn't match the cryptography-toolkit.

Reply to this note

Please Login to reply.

Discussion

I've tried BIP32, BIP44, 49, 84, and 86. All different from the toolkit. Something must be off...

Are you talking about this

bip39, bip44, slip44,

1237 0x800004d5 Nostr

I used bip39 for the first part, but that was just to confirm I had my bearings and was using the library correctly.

The thing I actually need is to be able to go from an xpub to a public key for a specific path.

Wouldn’t that be what the slip44 is for?

The slip has the registered coin types and I'm using Bitcoin from that list. BIP32 has the key derivation algorithm and I need that to match before it really makes sense to add on additional rounds of KDFs.

But it’s that how you deviate the path back to the master seed? Or am I just completely wrong.

The key derivation is defined here: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#user-content-Public_parent_key_rarr_public_child_key

BIP44 is about how many times that derivation is applied. So, BIP32 can stand on its own, but BIP44 can not. It requires the KDF from BIP32.

Also, you never deviate back to the master key, you can only go forward. It's an important detail, because if that ever were to change, all these privacy improvements would be lost, and also coins at risk in some very rare circumstamces.

Yeah I’ve been reading this for the last few days…trying to understand it.

I really appreciate you explanation here it makes a lot of sense.

Thank you.

I will try reading lots more….

Oh my gods, I think bitcoinlib has a bug in their key derivation!

I just tried the first test case from BIP32 and it got the right value for Chain m, but not for Chain m/0h

Yeah, here's my proof of work.

Library:

https://pypi.org/project/bitcoinlib/

Test vectors from: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki

Python code to repro the error:

from bitcoinlib.keys import HDKey

m = HDKey.from_seed('000102030405060708090a0b0c0d0e0f')

assert m.wif_public() == 'xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8'

assert m.wif_private() == 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi'

c1 = m.subkey_for_path("m/0")

assert c1.wif_public() == 'xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw'

# fails here ^

assert c1.wif_private() == 'xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7'

what if

# m/0'

c1 = m.subkey_for_path("m/0'")

I think I tried it with and without the single ticks and they seemed to be ignored. I believe the index is an integer type in the code, which is why I decided to experiment with the prime marker.

I saw the public_bytes has the prefix on it, making it a 33 byte string instead of 32 bytes. However, changing that didn't fix it. So if that is a problem, it's not the only problem.

I'll make sure my code matches however it is written in BIP32 before I post my code again though, just to reduce confusion.

OK, accroding gto BIP32 the ser(P) function *does* include the prefix byte, so that part of the code appears correct after all.