diff --git a/N-of-N-Seed-Splitting,-Theory-and-Practice.md b/N-of-N-Seed-Splitting,-Theory-and-Practice.md new file mode 100644 index 0000000..ed47ab2 --- /dev/null +++ b/N-of-N-Seed-Splitting,-Theory-and-Practice.md @@ -0,0 +1,119 @@ +### Contents ++ [N-of-N Seed Splitting: A Theoretical Introduction](#a_nn) ++ [Seed Splitting with MMGen](#a_ss) + +#### N-of-N 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 without 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 *P* in the previous example, *share1* is +a random value with the same bit length as *seed,* and *share2* is +the resulting “ciphertext”. Just as the ciphertext reveals nothing about the +plaintext in the previous example, *share2* reveals nothing about +*seed* without knowledge of *share1.* And *share1,* of +course, being a random value, reveals nothing about *seed* either. 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 arbitrary length can be created by +using an arbitrary number of random shares: + +Perform an *n*-way split: + +![]["seed ⊕ share1 ⊕ share2 ... ⊕ shareN-1 = shareN"] + +Recover the seed: + +![]["share1 ⊕ share2 ... ⊕ shareN = seed"] + +Knowledge of anything less than *n* shares reveals nothing about the seed. + +#### Seed Splitting with MMGen + +The MMGen wallet implements seed-splitting functionality via the commands +`mmgen-seedsplit` and `mmgen-seedjoin`. + +TBD + +[⊕]: 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" + +[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