From 59368fd7c1cf094696ba896a50b4530b7ed5913c Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Thu, 9 Jun 2022 11:18:08 +0000 Subject: [PATCH] add 3 wiki pages Added: - doc/wiki/using-mmgen/Test-Suite.md - doc/wiki/using-mmgen/Tool-API.md - doc/wiki/using-mmgen/XOR-Seed-Splitting:-Theory-and-Practice.md --- doc/wiki/using-mmgen/Test-Suite.md | 193 ++++++++++ doc/wiki/using-mmgen/Tool-API.md | 73 ++++ ...XOR-Seed-Splitting:-Theory-and-Practice.md | 342 ++++++++++++++++++ 3 files changed, 608 insertions(+) create mode 100644 doc/wiki/using-mmgen/Test-Suite.md create mode 100644 doc/wiki/using-mmgen/Tool-API.md create mode 100644 doc/wiki/using-mmgen/XOR-Seed-Splitting:-Theory-and-Practice.md diff --git a/doc/wiki/using-mmgen/Test-Suite.md b/doc/wiki/using-mmgen/Test-Suite.md new file mode 100644 index 00000000..4a2addfb --- /dev/null +++ b/doc/wiki/using-mmgen/Test-Suite.md @@ -0,0 +1,193 @@ +## Introduction + +In addition to low-level subsystems, the suite tests the overall operation of +MMGen’s commands by running them interactively as a user would. Thus the test +suite is useful not only for ensuring the MMGen system is correctly installed +and working on your platform but also for learning how it works. + +BTC-only testing requires only Bitcoin Core to be installed. Altcoin testing +requires various helper programs and libraries. Installation instructions for +these are provided below. Non-standard RPC ports and data directories are +always used, so there’s no need to stop your running node or nodes. + +On Linux/x86\_64 with a reasonably fast processor, the full suite should run in +under 15 minutes when invoked with the `-F` option. Execution times on other +platforms may be much slower. + +## Quick start + +### Container setup (if applicable) + +The test suite requires the `/dev/loopX` devices to exist and be enabled. If +you’re running in an LXC container, note that only privileged containers allow +loop devices. You may enable them in the config file as follows: + + lxc.cgroup2.devices.allow = b 7:0 rwm # /dev/loop0 + lxc.cgroup2.devices.allow = b 7:1 rwm # /dev/loop1 + lxc.cgroup2.devices.allow = b 7:2 rwm # /dev/loop2 + +Every time the container is started, you may need to create the files afresh: + + # mknod /dev/loop0 b 7 0 + # mknod /dev/loop1 b 7 1 + # mknod /dev/loop2 b 7 2 + +### BTC-only testing + +Clone the Bitcoin Core repo somewhere on your system: + + $ git clone https://github.com/bitcoin/bitcoin + +Install the Bitcoin Core daemon [(source)][sd] [(binaries)][bd]. + +Point the test suite to your copy of the Bitcoin Core repo: + + $ export CORE_REPO_ROOT=/path/to/bitcoin/core/repo + +Install Pycoin: + + $ python3 -m pip install --user pycoin + +CD to the MMGen repository root and build without installing: + + $ cd path/to/mmgen/repo + $ python3 setup.py build_ext --inplace + +Run the following if upgrading from a previous version of MMGen: + + $ test/test.py clean + +Run the test suite in fast mode, skipping altcoin tests: + + $ test/test-release.sh -F noalt + +### Complete testing (BTC plus all supported altcoins) + +Complete the BTC-only installation steps above, without running the test. + +Make sure the [Bitcoin Cash Node][cnd], [Litecoin][ld] and [Monero][md] +daemons are installed on your system. + +Install [OpenEthereum, Parity, Geth, the Ethereum dependencies][oe] and +optionally the [Solidity compiler][sc] as described on the +Altcoin-and-Forkcoin-Support page. + +In addition, you must install the following helper programs and libraries (MSYS2 +users can omit Zcash-Mini and leave out `sudo` in commands): + +#### SSH daemon setup (MSYS2 only) + +The XMR test sets up a local SOCKS proxy to test transaction relaying. This +requires the SSH daemon to be set up and running. On MSYS2 systems, SSHD +is not configured by default, but it may be easily set up with the following +steps: + +Open PowerShell as administrator, and at the DOS prompt, execute: + + system32> net user administrator /active:yes + system32> C:\\msys64\usr\bin\bash.exe --login + +Now, at the MSYS2 prompt, cd to the MMGen repository root and run the setup +script: + + $ scripts/msys2-sshd-setup.sh + +The daemon should now start automatically every time the system is booted. It +may also be started and stopped manually at the DOS or MSYS2 prompt as follows +(PowerShell must be running with admin privileges): + + # net start msys2_sshd + # net stop msys2_sshd + +#### MoneroPy + + $ git clone https://github.com/bigreddmachine/MoneroPy + $ cd MoneroPy + $ python3 setup.py install --user + $ cd .. + +#### Vanitygen PlusPlus (forked from Vanitygen Plus) + + $ git clone https://github.com/10gic/vanitygen-plusplus + $ cd vanitygen-plusplus + $ git checkout -b vanitygen-plus e7858035d092 # rewind to fork commit + $ make keyconv # ‘mingw32-make.exe keyconv’ for MSYS2 + $ sudo install --strip keyconv /usr/local/bin # ‘keyconv.exe’ for MSYS2 + $ cd .. + +#### Zcash-Mini + + $ sudo apt-get install golang # skip this if Go is already installed + $ git clone https://github.com/FiloSottile/zcash-mini + $ cd zcash-mini + $ go mod init zcash-mini + $ go mod tidy + $ go build -mod=mod # or just ’go build’ + $ sudo install --strip ./zcash-mini /usr/local/bin + $ cd .. + +#### Ethkey + +On Arch Linux systems, ethkey is included in the OpenEthereum package: + + $ pacman -S openethereum + +For other systems, you may have to build ethkey from source: + + $ sudo apt-get install rustc # skip this if Rust is already installed + $ git clone https://github.com/openethereum/openethereum + $ cd openethereum + $ git checkout v2.6.6 # this version builds on ARM boards - your mileage may vary + $ cargo build -p ethkey-cli --release + $ sudo install --strip ./target/release/ethkey /usr/local/bin + $ cd .. + +#### Monero note + +The Monero test (`test/test-release.sh xmr`) creates a private network and +mines coins, so is therefore non-deterministic and prone to random failures. +If you experience such a failure, just restart the test. + +### Run the tests + +Now you can run the test suite for all coins: + + $ test/test-release.sh -F + +## Overview of the individual tests + +`test/test-release.sh` is just a simple shell script that invokes the test +scripts with various options and arguments to ensure complete coverage of +MMGen’s functionality. Launch the script with the `-t` option to view the +invocations without running them. + +The test scripts themselves are all located in the `test/` directory and bear +the `.py` extension. They may be run individually if desired. Options and +arguments required by the tests are described in detail on their help screens. + +High-level testing of the MMGen system is performed by `test/test.py`, which +uses the `pexpect` library to simulate interactive operation of MMGen user +commands. Running `test/test.py` with the `-e` option will display the +commands’ output on the screen as they’re being run. + +| Test | What it tests | +|:----------------------|:-----------------------------------------------------| +| `test/colortest.py` | terminfo parsing; terminal colors | +| `test/gentest.py` | key/address generation - profiling and data validity | +| `test/hashfunc.py` | native SHA2 and Keccak implementations | +| `test/objtest.py` | MMGen data objects - creation and error handling | +| `test/objattrtest.py` | MMGen data objects - immutable attributes | +| `test/scrambletest.py`| HMAC scramble strings used in key/password derivation| +| `test/test.py` | overall operation of MMGen commands | +| `test/tooltest.py` | the `mmgen-tool` utility - overall operation | +| `test/tooltest2.py` | the `mmgen-tool` utility - data validity | +| `test/unit_tests.py` | low-level subsystems | + +[sd]: Install-Bitcoind-from-Source-on-Debian-or-Ubuntu-Linux +[bd]: Install-Bitcoind +[md]: https://getmonero.org/downloads/#linux +[ad]: https://download.bitcoinabc.org/ +[cnd]: https://bitcoincashnode.org/ +[ld]: https://download.litecoin.org/litecoin-0.17.1/ +[oe]: Altcoin-and-Forkcoin-Support#a_oe +[sc]: Altcoin-and-Forkcoin-Support#a_dt diff --git a/doc/wiki/using-mmgen/Tool-API.md b/doc/wiki/using-mmgen/Tool-API.md new file mode 100644 index 00000000..f86cfc0f --- /dev/null +++ b/doc/wiki/using-mmgen/Tool-API.md @@ -0,0 +1,73 @@ +The tool API provides a convenient interface to selected methods in the +mmgen.tool module. Type `pydoc3 mmgen.tool.api` for available methods and +call signatures. + +## Examples + +### Initialize: + + from mmgen.tool.api import tool_api + tool = tool_api() + +### Key/address generation: + + # List available coins: + print(' '.join(tool.coins)) + + # Initialize a coin/network pair: + proto = tool.init_coin('btc','mainnet') + + # Print the available address types for current coin/network, along with a + # description. If tool.addrtype is unset, the first-listed will be used: + tool.print_addrtypes() + + # Set the address type to P2PKH with compressed public key: + tool.addrtype = 'compressed' + + # Skip user entropy gathering (not recommended) + tool.usr_randchars = 0 + + # Generate a random hex secret: + hexsec = tool.randhex() + + # Generate the key and address: + wif = tool.hex2wif(hexsec) + addr = tool.wif2addr(wif) + + # Generate an LTC regtest Segwit key and address: + proto = tool.init_coin('ltc','regtest') + tool.addrtype = 'segwit' + wif = tool.hex2wif(hexsec) + addr = tool.wif2addr(wif) + + # Generate a random LTC regtest Bech32 key/address pair: + tool.addrtype = 'bech32' + wif,addr = tool.randpair() + +### Mnemonic seed phrase generation: + + # Generate an MMGen native mnemonic seed phrase: + mmgen_seed = tool.hex2mn(hexsec) + + # Generate a BIP39 mnemonic seed phrase: + bip39_seed = tool.hex2mn(hexsec,fmt='bip39') + +### Utility methods: + + # Reverse the hex string: + hexsec_rev = tool.hexreverse(hexsec) + + # Get the HASH160 of the value: + sec_hash160 = tool.hash160(hexsec) + + # Convert the value to base58 format: + sec_b58 = tool.hextob58(hexsec) + + # Convert the value to base58 check format: + sec_b58chk = tool.hextob58chk(hexsec) + + # Convert the byte specification '4G' to an integer: + four_g = tool.bytespec('4G') + + # Convert the byte specification '4GB' to an integer: + four_gb = tool.bytespec('4GB') diff --git a/doc/wiki/using-mmgen/XOR-Seed-Splitting:-Theory-and-Practice.md b/doc/wiki/using-mmgen/XOR-Seed-Splitting:-Theory-and-Practice.md new file mode 100644 index 00000000..765a7efc --- /dev/null +++ b/doc/wiki/using-mmgen/XOR-Seed-Splitting:-Theory-and-Practice.md @@ -0,0 +1,342 @@ +## Contents + ++ [XOR Seed Splitting: A Theoretical Introduction](#a_xor) + - [Deterministic Shares](#a_ds) + - [Named Splits](#a_ns) + - [Master Shares](#a_ms) ++ [Seed Splitting with MMGen](#a_ss) + +### XOR Seed Splitting: A Theoretical Introduction + +The bitwise exclusive-or operation (usually denoted as `XOR`, or “![⊕]”) +has interesting properties that make it very useful in cryptography. + +Suppose we have two bytes, *a* and *b*: + +![]["a: 1 0 0 1 0 1 0 0"] + +![]["b: 0 1 0 1 1 1 1 0"] + +To XOR the two bytes, we compare each of their bits. If the bit is the same for +both *a* and *b,* the corresponding bit of the result is 0. If it differs, the +result is 1: + +![]["a ⊖ b: 1 1 0 0 1 0 1 0"] + +Thus XOR can be thought of logically as “one or the other but not both”, or +arithmetically as addition [modulo][wm] 2 without carry, since 1 plus 1 equals 0 +in base-2 arithmetic. + +As is clear from our above example, switching the order of *a* and *b* has no +effect on the result. So XOR, like addition, is commutative: + +![]["a ⊕ b = b ⊕ a"] + +And like addition, grouping has no effect on the result. XOR is associative: + +![]["a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c"] + +But unlike addition, XOR has an extra property: *invertibility.* The result can +be switched with any of the operands, making XOR sort of like addition and +subtraction rolled into one. Thus, if + +![]["a ⊕ b = c"] + +then + +![]["c ⊕ a = b"] + +![]["b ⊕ c = a"] + +and so forth. + +This last property makes XOR very handy for encryption and decryption. Given +a plaintext *P* and a random value *r* with the same bit length as *P*, we +encrypt *P* by XOR’ing it with *r* to obtain the ciphertext *C:* + +![]["P ⊕ r = C"] + +To decrypt, we just XOR the ciphertext with *r* to recover the plaintext: + +![]["C ⊕ r = P"] + +The randomness of the ciphertext is guaranteed to be no less than that of the +random value. Thus if *r* is perfectly random, then *C* is perfectly +undecipherable, given no knowledge of *r.* This is the principle underlying the +[one-time pads][otp] used by spies and diplomats before the computer age, as +well as modern [stream ciphers][sc]. + +To demonstrate how this can be used for seed splitting, all we do is change +the names of the variables: + +![]["seed ⊕ share1 = share2"] + +Here *seed* is analogous to the plaintext *P,* *share*1 is a random +value with the same bit length as *seed,* and *share*2 is the +resulting ciphertext. Just as the *C* reveals nothing about *P* in the previous +example, *share*2 reveals nothing about *seed* without knowledge of +*share*1. To recover the seed, we just XOR the two shares. Since XOR +is commutative, the order in which we combine them isn’t important: + +![]["share2 ⊕ share1 = seed"] + +Thanks to XOR’s associativity, splits of any arbitrary length *n* can be created +by using *n*-1 random shares, with the *n*-th share being the result of the +chained XOR operations: + +Perform an *n*-way split: + +![]["seed ⊕ share1 ⊕ share2 ... ⊕ shareN-1 = shareN"] + +Join shares 1 through *n* to recover the seed: + +![]["share1 ⊕ share2 ... ⊕ shareN = seed"] + +Knowledge of any combination of *n*-1 shares reveals nothing about the seed. + +#### Deterministic Shares + +So we’ve seen that the mathematics behind XOR seed splitting is basically +trivial. In practice, though, there are several issues that need to be +resolved. For example, how do we obtain the random values for the shares? +The easy answer is to just use the random number generator provided by our +operating system. Generating the values deterministically is a better solution, +however, providing us with two key advantages: 1) we avoid reliance on such +factors as the quality of our OS RNG, the underlying hardware, and the entropy +pool; and 2) we gain reproducibility—the ability to generate identical shares +repeatedly, and as a consequence, to generate shares independently of each +other. + +This latter feature is especially useful. Suppose I want to do a 2-way split +of my seed for backup purposes, giving one share to my friend Bob and storing +the other share at some location accessible to me but unknown to Bob. With +deterministic shares, I can generate Bob’s share now, giving it to Bob, and my +own share later, once I’ve determined a good location for its safekeeping. And +if either of us loses our share, it can just be regenerated. + +OK, so now that we’re sold on the idea of deterministic shares, how do we go +about creating them? A naive approach would be to just generate a secure +cryptographic hash of our seed using the SHA256 algorithm and use that directly +as the first share: + +![]["share1 = SHA256(seed)"] + +This would work fine for a 2-way split: assuming SHA256 is secure and our seed +is strongly random (if either assumption is false, we’re in big trouble anyway), +then *share*1 is strongly random too and reveals nothing about our +seed. And being derived from the seed alone, it’s regenerable on demand by the +seed’s owner. + +For *n*-way splits where *n* is greater than 2, however, we run into a problem +when attempting to generate the additional random values. We might be tempted +to just keep hashing: + +![]["share2 = SHA256(share1), share3 = SHA256(share2), ..."] + +But you may have already spotted the mistake here: the owner of the first share +can generate all the successive shares up to *n*-1. Without the final *n*’th +share he can’t recover the seed, but the whole benefit of having the additional +shares has been nullified. + +***Important disclaimer:*** *there are other reasons, beyond the scope of this +discussion, why using a bare hash of the seed as our random number source might +not be a good idea. Bear in mind that this is a simplified **theoretical** +introduction, and the examples presented herein are not suitable for +implementation in real production code.* + +The above example illustrates what happens when we violate the golden rule of +the wallet developer: *never derive a secret from another secret that someone +besides the wallet’s owner could potentially gain access to.* This goes for +the private keys of the addresses in a wallet, which could be compromised in a +security breach. And it certainly goes for seed shares, which are intended for +distribution to others from the outset. + +The solution to this problem is to derive the shares directly from the seed, but +with an added identifier that’s unique to each share. The [HMAC] message-digest +algorithm is ideally suited for this: + +![]["share1 = HMAC(seed,'share1'), share2 = HMAC(seed,'share2'), ... shareN-1 = HMAC(seed,'share')"] + +Using these unique pseudorandom values, we can now split and rejoin our seed in +the manner described at the end of the previous section. + +#### Named Splits + +Now, we’d like to use seed splitting as part of our backup strategy, entrusting +shares of our seed with various people we know. Multiple 2-way splits seems +like the best approach—if one of our trustees loses their share, moves to +another city, or gets run over by a bus, then we have the others left as a +fallback. + +However, we have no mechanism as yet for generating multiple splits: using the +deterministic method outlined above, we can only generate the same set of +pseudorandom shares over and over again. The obvious solution here is to give +each split a name: for our split with Bob, we’ll add “bob” to the share +identifier, for our split with Alice, we’ll add “alice”, and so forth. Using +this approach, we can create an arbitrary number of uniquely named splits. + +Create a 2-way split with Bob: + +![]["share_me = HMAC(seed,'bob:share1'), share_bob = seed ⊕ share_me"] + +Create a 2-way split with Alice: + +![]["share_me = HMAC(seed,'alice:share1'), share_alice = seed ⊕ share_me"] + +In addition, we should handle the case of multiple splits with different length +but the same name. To exclude the reuse of shares in this case, we’ll add an +additional identifier field specifying the total number of shares in the split. + +Create a 3-way split “friends” with Bob and Alice: + +![]["share_me = HMAC(seed,'friends:share1:of3'), share_bob = HMAC(seed,'friends:share2:of3'), share_alice = seed ⊕ share_me ⊕ share_bob"] + +Create a 4-way split “friends” with Bob, Alice and Carol: + +![]["share_me = HMAC(seed,'friends:share1:of4'), share_bob = HMAC(seed,'friends:share2:of4'), share_alice = HMAC(seed,'friends:share3:of4'), share_carol = seed ⊕ share_me ⊕ share_bob ⊕ share_alice"] + +Thus we’ve ensured the uniqueness of all shares across all possible splits. + +#### Master Shares + +As the number of splits we create grows, the question of how to store our shares +becomes especially problematic. Each new split creates another new share that +must be securely stored somewhere. What we need is some mechanism to generate +our share of each split from a single master share. This master share would +need to be generated and stored just once, saving us a great deal of trouble. + +Having multiple master shares could be useful too. For example, if we ever +wanted to revoke our splits, all we’d have to do is destroy our copy of the +current master share, ensuring that none of the splits made with its +participation could be joined. To create new splits, we’d use the next master +share. + +This is all easy to implement using the tools we’re already familiar with from +the preceding sections. Using HMAC-SHA256, we’ll generate a range of indexed +master shares from our seed as follows: + +![]["master1 = HMAC(seed,'master1'), master2 = HMAC(seed,'master2'), ..."] + +Using master share #1 as our share, our 4-way split “friends” with Bob, Alice +and Carol now looks like this: + +![]["share_me = master1, share_bob = HMAC(seed,'friends:share2:of4:master1'), share_alice = HMAC(seed,'friends:share2:of4:master1'), share_carol = seed ⊕ HMAC(master1,'friends:share1:of4') ⊕ share_bob ⊕ share_alice"] + +And rejoining the seed looks like this: + +![]["seed = HMAC(master1,'friends:share1:of4') ⊕ share_bob ⊕ share_alice ⊕ share_carol"] + +The rejoining process now involves more than a simple XOR’ing of shares: The +name of the split must be input to the join function, so it should something +that’s easy to memorize. If you *really* don’t trust yourself to remember +the word “friends”, you could write it down somewhere. + +Also note that an additional field, `master`, has been appended to the share +identifiers. This is to ensure that the shares of each master share split are +unique, and differ from their non-master-share counterparts. + +### Seed Splitting with MMGen + +The MMGen wallet implements the seed splitting and joining functionality +described above via the commands [`mmgen-seedsplit`][SS] and +[`mmgen-seedjoin`][SJ]. Usage examples can be found on the `mmgen-seedsplit` +help screen. + +Shares can be made from and exported to all supported MMGen wallet formats. +This means you can split a BIP39 seed phrase, for example, and output the share +back to BIP39 in one easy command: + + # Create share 1 of a 2-way split of the provided BIP39 seed phrase: + $ mmgen-seedsplit -o bip39 sample.bip39 1:2 + +Each share of a split has a unique share ID. The share IDs are displayed by +`mmgen-seedsplit` so that the user may record them for later reference. They +may also be viewed with the `mmgen-tool list_shares` command: + + # List the share IDs of a 2-way named split 'alice' of your default wallet: + $ mmgen-tool list_shares 2 id_str=alice + + Seed: 71CA5049 (256 bits) + Split Type: 2-of-2 (XOR) + ID String: alice + + Shares + ------ + 1: D0BBD210 + 2: 25F0BD65 + + # List the share IDs of a 3-way default split of provided BIP39 seed phrase: + $ mmgen-tool list_shares 3 wallet=sample.bip39 + + Seed: 03BAE887 (128 bits) + Split Type: 3-of-3 (XOR) + ID String: default + + Shares + ------ + 1: 83B9AF74 + 2: 109485F4 + 3: 424522DC + +Share IDs are handy for checking the correctness of shares when rejoining a +split. Let’s say you’ve decided to rejoin your 2-way split with Alice, whose +share you exported to BIP39 format. This can be done by contacting Alice by +phone, for example, and having her read the mnemonic phrase to you. If the ID +of Alice’s share as displayed by `mmgen-seedjoin` matches the value you recorded +when making the split, then you know Alice has given you the correct phrase. + +***Note:*** *when recovering shares over an insecure channel like the telephone, +it’s advisable to destroy all copies of your share once you’ve rejoined the +seed to safeguard against a possible eavesdropping attacker.* + +Ordinary named splits can easily be rejoined even without the MMGen software. +First, each share must be converted to hexadecimal data. If your shares are in +BIP39 format, for example, there are command-line tools available to do this. +Then a single line of Python code is all that’s required to finish the job: + + $ python3 + >>> seed_hex = hex(int(share1_hex,16) ^ int(share2_hex,16)) # rejoin a 2-way split + +(Note that the XOR operator in Python is `^`.) + +Unfortunately, rejoining master-share splits is considerably harder to do at +the Python command prompt. This is because converting the master share into the +temporary share used to make the split involves an additional step, as you’ll +recall from the above discussion. In addition, this step is implemented by +MMGen somewhat differently than as described above. For advanced users, an +example will be provided in a future version of this document. + +[⊕]: https://mmgen.github.io/images/ss/o_xor.svg "⊕" +["a: 1 0 0 1 0 1 0 0"]: https://mmgen.github.io/images/ss/byte_a.svg "a: 1 0 0 1 0 1 0 0" +["b: 0 1 0 1 1 1 1 0"]: https://mmgen.github.io/images/ss/byte_b.svg "b: 0 1 0 1 1 1 1 0" +["a ⊖ b: 1 1 0 0 1 0 1 0"]: https://mmgen.github.io/images/ss/byte_ab.svg "a ⊖ b: 1 1 0 0 1 0 1 0" +["a ⊕ b = b ⊕ a"]: https://mmgen.github.io/images/ss/ab-ba.svg "a ⊕ b = b ⊕ a" +["a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c"]: https://mmgen.github.io/images/ss/abc.svg "a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c" +["a ⊕ b = c"]: https://mmgen.github.io/images/ss/ab-c.svg "a ⊕ b = c" +["c ⊕ a = b"]: https://mmgen.github.io/images/ss/ca-b.svg "c ⊕ a = b" +["b ⊕ c = a"]: https://mmgen.github.io/images/ss/bc-a.svg "b ⊕ c = a" +["P ⊕ r = C"]: https://mmgen.github.io/images/ss/Pr-C.svg "P ⊕ r = C" +["C ⊕ r = P"]: https://mmgen.github.io/images/ss/Cr-P.svg "C ⊕ r = P" +["seed ⊕ share1 = share2"]: https://mmgen.github.io/images/ss/ss-enc.svg "seed ⊕ share1 = share2" +["share2 ⊕ share1 = seed"]: https://mmgen.github.io/images/ss/ss-dec.svg "share2 ⊕ share1 = seed" +["seed ⊕ share1 ⊕ share2 ... ⊕ shareN-1 = shareN"]: https://mmgen.github.io/images/ss/ssN-enc.svg "seed ⊕ share1 ⊕ share2 ... ⊕ shareN-1 = shareN" +["share1 ⊕ share2 ... ⊕ shareN = seed"]: https://mmgen.github.io/images/ss/ssN-dec.svg "share1 ⊕ share2 ... ⊕ shareN = seed" +["share1 = SHA256(seed)"]: https://mmgen.github.io/images/ss/sha256.svg "share1 = SHA256(seed)" +["share2 = SHA256(share1), share3 = SHA256(share2), ..."]: https://mmgen.github.io/images/ss/sha256b.svg "share2 = SHA256(share1), share3 = SHA256(share2), ..." +["share1 = HMAC(seed,'share1'), share2 = HMAC(seed,'share2'), ... shareN-1 = HMAC(seed,'share')"]: https://mmgen.github.io/images/ss/hmac.svg "share1 = HMAC(seed,'share1'), share2 = HMAC(seed,'share2'), ... shareN-1 = HMAC(seed,'share')" +["share_me = HMAC(seed,'bob:share1'), share_bob = seed ⊕ share_me"]: https://mmgen.github.io/images/ss/bob.svg "share_me = HMAC(seed,'bob:share1'), share_bob = seed ⊕ share_me" +["share_me = HMAC(seed,'alice:share1'), share_alice = seed ⊕ share_me"]: https://mmgen.github.io/images/ss/alice.svg "share_me = HMAC(seed,'alice:share1'), share_alice = seed ⊕ share_me" +["share_me = HMAC(seed,'friends:share1:of3'), share_bob = HMAC(seed,'friends:share2:of3'), share_alice = seed ⊕ share_me ⊕ share_bob"]: https://mmgen.github.io/images/ss/friends1.svg "share_me = HMAC(seed,'friends:share1:of3'), share_bob = HMAC(seed,'friends:share2:of3'), share_alice = seed ⊕ share_me ⊕ share_bob" +["share_me = HMAC(seed,'friends:share1:of4'), share_bob = HMAC(seed,'friends:share2:of4'), share_alice = HMAC(seed,'friends:share3:of4'), share_carol = seed ⊕ share_me ⊕ share_bob ⊕ share_alice"]: https://mmgen.github.io/images/ss/friends2.svg "share_me = HMAC(seed,'friends:share1:of4'), share_bob = HMAC(seed,'friends:share2:of4'), share_alice = HMAC(seed,'friends:share3:of4'), share_carol = seed ⊕ share_me ⊕ share_bob ⊕ share_alice" +["master1 = HMAC(seed,'master1'), master2 = HMAC(seed,'master2'), ..."]: https://mmgen.github.io/images/ss/master.svg "master1 = HMAC(seed,'master1'), master2 = HMAC(seed,'master2'), ..." +["share_me = master1, share_bob = HMAC(seed,'friends:share2:of4:master1'), share_alice = HMAC(seed,'friends:share2:of4:master1'), share_carol = seed ⊕ HMAC(master1,'friends:share1:of4') ⊕ share_bob ⊕ share_alice"]: https://mmgen.github.io/images/ss/friends3.svg "share_me = master1, share_bob = HMAC(seed,'friends:share2:of4:master1'), share_alice = HMAC(seed,'friends:share2:of4:master1'), share_carol = seed ⊕ HMAC(master1,'friends:share1:of4') ⊕ share_bob ⊕ share_alice" +["seed = HMAC(master1,'friends:share1:of4') ⊕ share_bob ⊕ share_alice ⊕ share_carol"]: https://mmgen.github.io/images/ss/friends4.svg "seed = HMAC(master1,'friends:share1:of4') ⊕ share_bob ⊕ share_alice ⊕ share_carol" + + + +[HMAC]: https://en.wikipedia.org/wiki/HMAC +[wm]: https://en.wikipedia.org/wiki/Modular_arithmetic +[otp]: https://en.wikipedia.org/wiki/One-time_pad +[sc]: https://en.wikipedia.org/wiki/Stream_cipher +[SS]: seedsplit-[MMGen-command-help] +[SJ]: seedjoin-[MMGen-command-help]