Subwallets, Part 1: basic framework and subwallet generation

Beginning with this commit, every MMGen wallet now has a two sets of associated
subwallets with “long“ and “short” seeds.

MMGen wallets and subwallets are functionally equivalent and externally
indistinguishable.  This has benefits, especially for real-world security, as
well as drawbacks.  For more information, see the `mmgen-subwalletgen` help
screen: https://github.com/mmgen/mmgen/wiki/subwalletgen-[MMGen-command-help]

This patch provides subwallet generation functionality and subseed display
utilities.  Support for transaction signing and address generation using a
subwallet's parent wallet will be added in a forthcoming patch.

Examples:

    # Create a bogus wallet in mnemonic format for testing purposes:
    $ echo $(yes bee | head -n24) > bogus.mmwords

    # List the wallet's first five subseed pairs:
    $ mmgen-tool list_subseeds 1-5 wallet=bogus.mmwords
    Parent Seed: DF449DA4 (256 bits)

     Long Subseeds     Short Subseeds
     -------------     --------------
      1L: FC9A8735       1S: 930E1AD5
      2L: 62B02F54       2S: DF14AB49
      3L: 9E884E99       3S: AD3ABD98
      4L: DB595AE1       4S: 3E885EC4
      5L: 36D5A0D1       5S: 30D66FF5

    # Generate the 5th short (128-bit) subwallet from the wallet:
    $ mmgen-subwalletgen bogus.mmwords 5S

    # Same as above, but output subwallet to mnemonic (seed phrase) format:
    $ mmgen-subwalletgen -o mn bogus.mmwords 5S
    ...
    Mnemonic data written to file '30D66FF5[128].mmwords'

    # View the subwallet's seed phrase:
    $ cat 30D66FF5[128].mmwords
    object capture field heart page observe road bond mother loser really army

    # Generate 10 addresses from the subwallet seed phrase:
    $ mmgen-addrgen 30D66FF5[128].mmwords 1-10
    ...
    Addresses written to file '30D66FF5[1-10].addrs'
This commit is contained in:
The MMGen Project 2019-05-12 12:29:35 +00:00
commit 7538a9460e
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
16 changed files with 527 additions and 11 deletions

View file

@ -119,6 +119,15 @@ tests = OrderedDict([
('101,1,3,5,2-7,99',[1,2,3,4,5,6,7,99,101]),
({'idx_list':AddrIdxList('1-5')},[1,2,3,4,5])
)}),
('SubSeedIdxRange', {
'bad': (33,'x','-11','66,3','0','3-2','8000000','100000000',(1,2,3)),
'good': (
('3',(3,3)),
((3,5),(3,5)),
('1-2',(1,2)),
(str(g.subseeds),(g.subseeds,g.subseeds)),
(str(SubSeedIdxRange.max_idx),(SubSeedIdxRange.max_idx,SubSeedIdxRange.max_idx)),
)}),
('BTCAmt', {
'bad': ('-3.2','0.123456789',123,'123L','22000000',20999999.12345678),
'good': (('20999999.12345678',Decimal('20999999.12345678')),)
@ -147,6 +156,10 @@ tests = OrderedDict([
'я',r32,'abc'),
'good': (({'sid':'F00BAA12'},'F00BAA12'),(Seed(r16),Seed(r16).sid))
}),
('SubSeedIdx', {
'bad': (33,'x','я','1x',200,'1ss','L','s','200LS','30ll','s100',str(SubSeedIdxRange.max_idx+1),'0'),
'good': (('1','1L'),('1s','1S'),'20S','30L',('300l','300L'),('200','200L'),str(SubSeedIdxRange.max_idx)+'S')
}),
('MMGenID', {
'bad': ('x',1,'f00f00f','a:b','x:L:3','F00BAA12:0','F00BAA12:Z:99'),
'good': (('F00BAA12:99','F00BAA12:L:99'),'F00BAA12:L:99','F00BAA12:S:99')