Recovering Tokens from Lost Private Keys and Expired Outputs

2024-05-24 · Ryan X. Charles

tldr: The new default output type includes a second key from a semi-trusted “recovery service”, which can be any user but will by default be the wallet service provider chosen by the user, which gains access to all outputs after 60 days and spends the tokens back to the user in case the user has lost their keys. To prevent the recovery service from gaining access to your tokens, simply log in at least once per 60 days and rotate your keys.


Why Recovery?

There are two types of wallets:

  • Custodial: A service manages keys for the user, like exchanges. The user authenticates with identity information such as email, phone, and government ID, and does not need to manage private keys. However, they must trust the custodial service not to mismanage the keys.
  • Self-custodial: The user manages their own keys. The user does not need to trust any third-party, but the user must keep their keys secure and must not lose them, or they will lose access to their tokens.

Most users of cryptocurrency use custodial wallets, and I see no reason why that will change with EarthBucks.

That said, the first wallet I am building is self-custodial because it is very important for users who actually do want to manage their own keys that this service exists. It is particularly important for businesses who want to offer custodial services for their users.

One of the things I learned building Bitcoin wallets for more than 10 years is that even highly sophisticated and technical users will lose their keys and therefore lose access to their tokens.

To account for the extremely frequent scenario of key loss, and also for what I expect will be frequent cases of key loss through inactivity because all UTXOs on EarthBucks expire, I have added a new script type to EarthBucks called recovery. The recovery script is a way for a semi-trusted third party to recover outputs after 60 days if the user has lost their key or if they are simply inactive.

The way it works is like this:

  • From 0 days to 60 days, the user can spend their own tokens with their own private key. It is expected that the user will rotate their keys every 60 days by logging in and pressing a button.
  • After 60 days, if the user has not rotated their keys, a recovery service will become active. The recovery service, in most cases, will be the wallet company that the user is using. For instance, I plan to host a recovery service at earthbucks.com. The recovery service will automatically re-send the tokens back to the user after 60 days, minus a small recovery fee agreed to by the user.
  • After 90 days, if the output is still unspent, it will expire. This will only ever happen if both the user and the recovery service have lost their keys or are inactive, which is expected to be very rare.

I have previously explained how all UTXOs expire. In this post, I would like to explain how the recovery script works.

Script: Pub Key Hash Expiry with Recovery (PKHXR 90D 60D)

The new standard script type is called PKHXR 90D 60D which means the output will expire completely after 90 days if it is not spent and it will be taken by whichever mine mines that block. The 60 day period is when the recovery key becomes active. Technically, the recovery service can do anything it wants with the tokens after 60 days, but the default wallet software will simply send the tokens back to the same keys, minus a fee. The user will agree to a Terms of Service with the recovery service (their wallet) that will specify the behavior.

If the user has lost their keys, the user will authenticate with non-key material such as phone, email, and government ID, and they will tell the recovery service (their wallet) that they have lost their keys. In that case, the next time the recovery period is active, the recovery service will send the tokens to a new user key.

The script relies on CHECKLOCKRELVERIFY with a total of three cases triggered by the spend script:

  • The standard branch where the user spends the output. This branch is always possible with the user’s key, but becomes impossible if the output is spent (of course).
  • The expiry branch, which is common for all scripts on EarthBucks, for now and into the future. After 90 days, the output expires. While the user could technically spend the tokens after expiry, that will never happen, because output will be spent a by a mine and the tokens will be distributed to miners.
  • The recovery branch, which becomes possible after 60 days. The recovery service (which could technically be any user) will be able to spend the output after 60 days. Again, technically, the recovery service could spend the output after 90 days, but that will never happen, because by then the output will be taken by a mine. The recovery service can do whatever it wants with the tokens at this time, which will presumably be to follow whatever contract it has with the user, which in the default case will be to send the tokens back to the same default user output key, unless the user has authenticated with the service and told it that the keys are lost.

The PKHXR 90D 60D output script looks like this:

OP_IF
OP_DUP
OP_DOUBLEBLAKE3
OP_PUSHDATA1
[32 bytes: the user's pub key hash]
OP_EQUALVERIFY
OP_CHECKSIG
OP_ELSE
OP_IF
OP_PUSHDATA1
[2 bytes: the number 8640]
OP_CHECKLOCKRELVERIFY
OP_DROP
OP_DUP
OP_DOUBLEBLAKE3
OP_PUSHDATA1
[32 bytes: the recovery service's pub key hash]
OP_EQUALVERIFY
OP_CHECKSIG
OP_ELSE
OP_PUSHDATA1
[2 bytes: the number 12960]
OP_CHECKLOCKRELVERIFY
OP_DROP
OP_1
OP_ENDIF
OP_ENDIF

Note:

  • The number 8640 is the number of blocks in 60 days.
  • The number 12960 is the number of blocks in 90 days.

The default spend script, created by the user, and expected to be used from 0 - 60 days, looks like this:

OP_PUSHDATA1
[65 bytes: the user's signature]
OP_PUSHDATA1
[33 bytes: the user's public key]
OP_1

The recovery spend script, created by the recovery service, and which becomes possible after 60 days, looks like this:

OP_PUSHDATA1
[65 bytes: the recovery service's signature]
OP_PUSHDATA1
[33 bytes: the recovery service's public key]
OP_1
OP_0

The expiry spend script, created by a mine, and which becomes possible after 90 days, looks like this:

OP_0
OP_0

The recovery service has a 30 day window to do whatever it needs to do to get the funds back to the user. The default behavior is to re-spend the output back to the user minus a fee, however, other behaviors are possible. For instance, the recovery service could collect all recovery outputs in a 30 day window and merge them after 30 days to decrease the total number of transactions. Any other behavior is possible within the range. The recovery service may take a fee per output, or the fee could be paid some other way, such as a monthly fee by the user.

Note that the recovery script is optional. The user can use “PKHX” transaction outputs, which are also standard, and do not have a recovery key. However, those outputs also expire after 90 days. The recovery type is strictly better, because in both cases, active users have exclusive access to their funds. Only in the recovery case is there a way to recover tokens in the event the user loses their keys or becomes inactive. In the standard case, users will lose their tokens after 90 days. This is why recovery is the default behavior.

Conclusion

It is extremely common for users to lose their private keys, even for sophisticated, technical users. On EarthBucks, it is expected it will also be common that users become inactive and lose access to their funds through expiry. The solution to both of these cases is the recovery output type, PKHXR 90D 60D, which enables a recovery service chosen by the user to recover funds after a 60 day window. This both enables token recovery for lost keys and also prevents accidental expiry. Recovery is the default type and it is expected all users will use a recovery service, unless they are a sophisticated user, such as a business, with a specific need for alternate script types.


Earlier Blog Posts

Mines vs. Miners
2024-05-22 · Ryan X. Charles
Why All UTXOs Expire After 90 Days
2024-05-18 · Ryan X. Charles
Rust Result in TypeScript
2024-05-09 · Ryan X. Charles
42 Million EarthBucks
2024-05-08 · Ryan X. Charles

Back to Blog

Home · About · Blog · Privacy · Terms
X · Telegram · Discord · reddit · GitHub
Copyright © 2024 Ryan X. Charles LLC