Post
Topic
Board Armory
Re: 2-of-3 Paper Wallets
by
etotheipi
on 06/03/2013, 05:46:22 UTC
Well, you guys were too slow and I just did it anyway.  I also left out one critical reason:  I really wanted this feature for myself!   And I don't want to wait 2 months for it!   I knew it would take me a day, and I'm sure someone would benefit from it, now.  Also, it's not wasted effort -- it's more sample code for other users, and I got the fragment data structures ironed out which will be recycled when I implement it in the GUI.

I have tested the heck out of it, and successfully restored quite a few test wallets with it.  Let me know what you think!

  • Create M-of-N fragmented backup, for any value of N, and 2<=M<=8
  • Works with any Armory *.wallet files, encrypted or not (will prompt for passphrase if encrypted)
  • Creates N text files that can easily be opened and printed (sorry, no QR codes from terminal)
  • Deterministic fragments means you can re-print lost fragments, or create more later (increase N)
  • The git-commit version is put in the text file, in case you want to know exactly what version created it
  • Error correction up to one character per line.  Identifies which file&line has 2+ errors that can't be corrected automatically.
  • Use the "unfrag" script right after "fragging" to test recombining various subsets of fragment files (for your own peace of mind)
  • Endless error checking to make sure you get it right, or know what you did wrong.



Checkout the armoryd branch, and the scripts are in the extras directory.
Sorry, this only works if you can run python scripts (possible in Windows, but you have to install some stuff).
Code:
$ python frag_wallet.py ~/.armory/armory_2QQkCkdt_.wallet 3 5
$ python unfrag_wallet.py wallet_2QQkCkdt_frag*.txt --test
$ python unfrag_wallet.py wallet_2QQkCkdt_frag*.txt

Use the extras/frag_wallet.py script to break your paper backup in N files, and then you can immediately use the extras/unfrag_wallet.py script to execute the recovery process on 20 different subsets of M fragment files.   Without the --test option, it will ask you for the appropriate encryption options, and then create an armory*.wallet file that can imported natively into Armory.

Output of the fragging script
Code:
$  python frag_wallet.py ~/.armory/armory_2QQkCkdt_.wallet 3 5

********************************************************************************
* Executing wallet-fragmenting script.  Split your Armory wallet
* into N pieces, requiring any M to recover the wallet.
********************************************************************************

Found hash of current git commit: cf8ebe7cecf4bbd0457e8f984354aabb6e869e66
Here is the paper backup information for this wallet.

   Root Key:   hrfr dejf snwf rtun rtin dhri snor aihd wiut
               otjf osws teaa gjei ihoa ffaa fojn swng tusg
   Chaincode:  kwig jorj agtj ragt kwrn dnhf ojgw tkwg snti
               hdst aurh osfj ajhd nwra ogdd dsiw saff fwra

Will create 3-of-5 fragmentation of your paper backup.
Continue? [Y/n]: y
About to create the fragments.  Any other info/identifiers you would
like to add to each of the fragment files?  Enter it on the next line:
(Enter info or leave blank): This fragment belongs to forum user etotheipi    

Fragment 1: wallet_2QQkCkdt_frag1_need_3.txt
    ID: 0301 02d1 93af fa6f
    x1: aiow gnrr haaj hthf hsnf rskj tooi kjta ajuf
    x2: jgto kgir ekgs whod kdkr rwsr hase jdui irdh
    x3: rugh hoas sghk sowr esdj kgnw hihe jnri jehu
    x4: eagt fair gjan ifwd retd ewnd aofu gnur jdut
    y1: owrn sowu nfrw oeeo gggs ikkw feii ueja hwns
    y2: aogt osig wonk jkis fkur gfhk kowt gwdu tter
    y3: eats akge jeot rdug oeki frgd onia einn rddj
    y4: dkfj nsed tijj nfkn dkne nieu ittf gnrg gkhj

Fragment 2: wallet_2QQkCkdt_frag2_need_3.txt
    ID: 0302 02d1 93af fa6f
    x1: fadf gtko nwii gfwd nogk osak jodn tess dgdt
    x2: wris jthf kgdu jiwj jeho suii ugnw rewd rtoi

...

Fragment 5: wallet_2QQkCkdt_frag5_need_3.txt
    ID: 0305 02d1 93af fa6f
    x1: hfte nufh utis sseh aweu jkgw ugno iaow kdue
    x2: nkwo ndsw jief taar tfrg kejn knwg tfkt akuw
    x3: ofat fgui iwsk eofg toeo widn gwnh hauk knhg
    x4: ugut wfww rfon kdkg uddi rutn nefh ftid iorn
    y1: oerh rdie rnth dnda iaws ateg utaf drhh grnu
    y2: hrte iaoh khwa jrfa dfeh doej usit infh fjhj
    y3: uije nsga suod jiid sjau rhwh swsg rfgn gwud
    y4: nwnd eheo issg tdrw kdei fhoj joun iuit jirf

NOTE: If you rerun this fragment script on the same wallet
      with the same fragments-required value, M, then you will
      get the same fragments.  Use this to replace fragments,
      or using a higher N-value to produce more pieces (but you
      MUST use the same M value!)

Each file looks like the following:
Code:
Wallet ID:   2QQkCkdt
Create Date: 2013-Mar-06 12:29am
Git Commit:  cf8ebe7cecf4bbd0457e8f984354aabb6e869e66
This fragment belongs to forum user etotheipi

This Fragment:     #1
Fragments Needed:   3
Fragments Created:  5 (more fragments may have been created later)


The following is a single fragment of your wallet.  Execute
the reconstruction script with any 3 of these fragment files
in the execution directory to recover your original wallet.
Each file can be reconstructed by manually typing the data
into a text editor.  Only the following 9 lines (with prefixes)
are necessary in each file.  All other data can be omitted.

ID: 0301 02d1 93af fa6f
x1: aiow gnrr haaj hthf hsnf rskj tooi kjta ajuf
x2: jgto kgir ekgs whod kdkr rwsr hase jdui irdh
x3: rugh hoas sghk sowr esdj kgnw hihe jnri jehu
x4: eagt fair gjan ifwd retd ewnd aofu gnur jdut
y1: owrn sowu nfrw oeeo gggs ikkw feii ueja hwns
y2: aogt osig wonk jkis fkur gfhk kowt gwdu tter
y3: eats akge jeot rdug oeki frgd onia einn rddj
y4: dkfj nsed tijj nfkn dkne nieu ittf gnrg gkhj

Run the unfrag test: (it works without the --test flag, if you have more than M files)
Code:
$  python unfrag_wallet.py wallet_2QQkCkdt_frag*.txt --test

********************************************************************************
* Restoring wallet from 3-of-N fragmented backup!
********************************************************************************

Recovered paper backup: 2QQkCkdt

    hrfr dejf snwf rtun rtin dhri snor aihd wiut
    otjf osws teaa gjei ihoa ffaa fojn swng tusg
    kwig jorj agtj ragt kwrn dnhf ojgw tkwg snti
    hdst aurh osfj ajhd nwra ogdd dsiw saff fwra

Testing reconstruction on 20 subsets:
   Using fragments (0,1,3)  Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
   Using fragments (2,3,4)  Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
   Using fragments (1,3,4)  Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
   Using fragments (1,2,3)  Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
   Using fragments (0,1,2)  Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
   Using fragments (0,3,4)  Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
   Using fragments (0,3,4)  Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
   Using fragments (2,3,4)  Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
   Using fragments (0,2,4)  Reconstructed (first line): hrfr dejf snwf rtun rtin dhri snor aihd wiut
   ...

Recover the wallet:
Code:
$ python unfrag_wallet.py wallet_2QQkCkdt_frag*.txt

********************************************************************************
* Restoring wallet from 3-of-N fragmented backup!
********************************************************************************

Recovered paper backup: 2QQkCkdt

    hrfr dejf snwf rtun rtin dhri snor aihd wiut
    otjf osws teaa gjei ihoa ffaa fojn swng tusg
    kwig jorj agtj ragt kwrn dnhf ojgw tkwg snti
    hdst aurh osfj ajhd nwra ogdd dsiw saff fwra

You have supplied more pieces (5) than needed for reconstruction (3).
Are you trying to run the reconstruction test instead of actually
recovering the wallet?  If so, wallet recovery will be skipped.  [Y/n] n

Proceeding with wallet recovery...

Would you like to encrypt the recovered wallet? [Y/n]: y
Choose an encryption passphrase:
   Passphrase:
        Again:
Set the key-stretching parameters:
   Seconds to compute (default 0.25): 2
   Max RAM used, in MB (default 32):  16
Creating new wallet...
Please wait while the address pool is being populated....
Created armory_2QQkCkdt_recovered.wallet

Exhaustive error catching and useful information
Code:
$ python unfrag_wallet.py wallet_2QQkCkdt_frag*.txt --testnet
ERROR: Some files are duplicates!
   wallet_2QQkCkdt_frag1_need_3.txt is Fragment 1
   wallet_2QQkCkdt_frag2_need_3.txt is Fragment 1
   wallet_2QQkCkdt_frag4_need_3.txt is Fragment 4
Aborting

Code:
$ python unfrag_wallet.py wallet_2QQkCkdt_frag*.txt --testnet

********************************************************************************
* Restoring wallet from 3-of-N fragmented backup!
********************************************************************************

(WARNING) armoryengine.py:1235 - ***Checksum error!  Attempting to fix...
(WARNING) armoryengine.py:1259 - Checksum fix failed
ERROR:  Uncorrectable error
        File:  wallet_2QQkCkdt_frag1_need_3.txt
        Line:  y2