Between coding for CardanoKeys and my day job I do get the occasional odd request. Today two members of our Discord Server asked about how they could access a wallet using the “root.xsk” file.
That was intriguing!
The root.xsk file isn’t something very many people seem to know about but it is – fairly literally – the key to access anything on the wallet.
The way I personally learned to mint tokens on Cardano was this (now outdated but still useful) guide and the basics are still what other developers I’ve talked to use but it does not use the extended signing key (xsk). Instead all the usual guides ask the administrators and creators to generate their payment and verification keys using the cardano-cli which is now bundled in the cardano-node github repository.
Recently we’ve had some uncommon requirements at CardanoKeys.
Not only did we need a dedicated wallet to sell pre-minted NFTs at a high speed (our policy locked so we had the choice of using a second policy or pre-minting), we also needed to have that wallet available in Daedalus for emergency access.
In case I got abducted by aliens or other unlikely cases of me not being able to access the wallet anymore Tony – founder of CardaneKeys – wanted to be able to still have some way to access the NFTs.
IOHK provides a tool which helps with that task!
Using cardano-addresses allows creators to generate seed phrases, turn them into machine usable keys and allow us to have the wallet both available via Daedalus and via command-line tools.
The usual process is – reduced to a bare minimum – as follows:
– Generate a seed phrase
– Generate an extended signing key (the aforementioned root.xsk)
– Create a payment signing key
– Calculate the address associated with that key
I’ll go over the commands used for that later in this writeup since the creators of the challenge did put up a little bonus challenge in there.
Solving the challenge – a naive approach
The first “hint” wasn’t terribly subtle.
There is a text starting with “root_xsk” around the content of the ticket, it was not terribly subtle.
What was somewhat subtle, however, was that this key simply refused to work!
And – sadly – IOHK has not yet found the time to add useful error messages to a lot of their tools.
That’s not very helpful.
It’s just a way for the tool to say “We couldn’t properly use that input, something went wrong”.
Good thing there’s a second hint!
Within the Ponchos there’s the hint “ROT 5”.
ROT5 simply adds five to all the numbers while ignoring the letters.
That key worked!
Small distraction: Why turning the key into the seed phrase is impossible
It’s absolutely impossible to get the seed phrase from the root key, at least to the extend to my knowledge.
The seed phrase quite literally sets the cryptographic “seed” (the entropy to be used) for a one-way function which generates the actual private keys.
Just like turning some content into its hash it’s not possible to go the other way around. But, also like with hashes, getting to the same results if the content is known to – for example – verify the contents is easy.
Getting the address from the root.xsk
So getting to the wallet was fairly straightforward and with a few simple steps we could get to the address.
It’s not just empty, there also has never been any transaction going onto that address. There is also no staking address associated with that wallet either so there is no easy way to look up other addresses associated with that wallet.
TIL: How different addresses for wallets are generated
There are two Cardano improvement proposals which have helped me to understand what I ended up doing:
– CIP-1852 (clever)
Two of the above commands were pretty much just copied and pasted without really understanding what exactly they do. Both have used the string “1852H/1815H/0H/0/0”.
Let me break this down number for number:
– 1852 – The “purpose” of the wallet
– 1815 – The coin type of the wallet
– 0 – the account index of the wallet
– 0 – the role of the wallet
– 0 – the index of the wallet
Back in Byron “44” was used instead of 1852. This was changed since Byron used a different algorithm to generate addresses from public keys so this serves to distinguish how to handle the public key.
1852 was the year Ada Lovelace died, further tying her legacy into Cardano.
The coin type simply corresponds to “Cardano” for which the year of Ada Lovelace’s birth “1815” was chosen.
This one I honestly didn’t fully understand. It’s not very well documented in either CIP-1852 or CIP-1854.
This one is simple. “0” is for the wallet, “2” is for the staking key and “1” is reserved. So for regular wallets I’ll just need to set it to “0”.
This one can be any positive, signed 16-bit integer value but is usually incremental. Obviously “0” was a dud but that’s where I’d start to just brute force a correct number.
Finding the true solution
Since I only learned about this challenge today and it seemed fairly doable for five, cool NFTs I was a bit in a rush and just wrote a very dumb bash script. It’s not terribly well written, I usually prefer python and it for basically anything I’m not really used to handling variables in bash.
This basically just attempted to list all UTxOs for addresses associated with the private key and iterated from zero to 2000 on the wallet index while keeping everything else the same.
There is no automation to stop once it finds anything so I just kept it running for a few minutes on a second screen while working on something else. The UTxO is no longer there, having transferred out the tokens already, but at 420 the monotonous output of the code had a disruption and it turned out that the token plus a graciously offered 4.2 million Lovelaces in a second transaction were included on that address.
The last few steps were to recreate the steps of creating the non-extended payment signing key and manually creating a transaction to send these out.
I’d like to thank Schmmahla and collonill for pointing me to the challenge, ponchos.io for hosting a fun, little challenge and the KeyMunity for being as amazing as they are. There’s hardly a day I don’t get to learn something new thanks to them.
Also: You have my attention now, dear Ponchos team! I’ll definitely look into the clues the weaver has kindly left behind and maybe find something interesting along the way. Or at the very least learn something new.
See you around, my DMs on Discord ( [the Minister]#0001 ) are always open!
I did put a little /🚬 in the bottom right corner, but brute force always works. Thanks for taking the time to write this.