greenaddress / garecovery

GreenAddress recovery tool for 2of2 and 2of3 wallets
MIT License
107 stars 53 forks source link

2 of 2 sovereign recovery - provide more details how it works #49

Open landabaso opened 2 years ago

landabaso commented 2 years ago

I am trying to understand the details behind the 2-2 account sovereign recovery.

According to the docs, either of the 2 HD seeds: a) Green or b) my seed can access the funds after a year (or whatever).

So if I understood correctly, in case Blockstream disappeared, I could recover my funds after a year having only my seed.

From what I can guess, Blockstream Green may be using P2SH addresses (or P2WSH). So my guess is that a path of the locking script will let spend a UTXO after a while (CSV) with a single key.

But, in order to spend a P2SH, the full redeem script should also also required. Shouldn't it?

The question is, how can garecovery recover funds using only one seed?

Shouldn't I also need to store the complete script structure, the second public key (controlled by Blockstream) and the lock time used?

The script structure and the lock time used could be hardcoded, so no big deal. But, what about the public key you use on your side? Where is it stored if something happens to Blockstream?

Is perhaps Blockstream always using the same seed for all accounts and it also hardcodes that public key into garecovery?

Could you please guys explain a bit how these details work?

Thanks

jgriffiths commented 2 years ago

Side note: Can Blockstream also access my funds without my cooperation after one year if I forget about my wallet?

No, coins can never be moved with only the Green server key. The script used is (from wally sources):

    recovery = users key, main = green key

    /* The script we create is:
     *     <recovery_pubkey> OP_CHECKSIGVERIFY
     *     <main_pubkey> OP_CHECKSIG OP_IFDUP OP_NOTIF
     *         <CSV_BLOCK> OP_CHECKSEQUENCEVERIFY
     * OP_ENDIF
     * Solved by:
     * 1) The stack containing the main and and recovery signatures.
     * 2) The stack containing an empty signature and the recovery signature, and the CSV time having passed.
     */

Blockstream Green may be using P2SH addresses (or P2WSH).

p2sh or p2sh-p2wsh for multisig, yes.

Is perhaps Blockstream always using the same seed for all accounts and it also hardcodes that public key into garecovery?

Yes-ish - the Green root xpubs are public and hard-coded in each of our wallets and the recovery app:

# GreenAddress xpubs for mainnet/testnet
GA_KEY_DATA_MAINNET = {
    'chaincode': 'e9a563d68686999af372a33157209c6860fe79197a4dafd9ec1dbaa49523351d',
    'pubkey': '0322c5f5c9c4b9d1c3e22ca995e200d724c2d7d8b6953f7b38fddf9296053c961f',
}

GA_KEY_DATA_LIQUID = {
    'chaincode': '02721cc509aa0c2f4a90628e9da0391b196abeabc6393ed4789dd6222c43c489',
    'pubkey': '02c408c3bb8a3d526103fb93246f54897bdd997904d3e18295b49a26965cb41b7f'
}

There are only limited CSV lock time values allowed per network:

CSV_BUCKETS = {
   'mainnet': [25920, 51840, 65535],
    'liquid': [65535],
} 

The user level green xpubs are derived using a long path derived from the users mnemonics using a one way function. See garecovery/ga_xpub.py in the sources of this repo for details.

The users subaccount xpubs are derived using the subaccount number, the simplest documentation of the exact derivation scheme is probably in gdk, in the comments of src/xpub_hdkey.hpp. Its also implemented here in recovery of course, but not all in one place like that header.

Shouldn't I also need to store the complete script structure, the second public key (controlled by Blockstream) and the lock time used?

Given the above, enumerating and scanning the users addresses is fairly trivial, see scan_subaccount in garecovery/two_of_two_csv.py for details of iterating.

Hope this helps.