new file: Seed-Splitting,-Theory-and-Practice.md
parent
26bcea75e7
commit
545d92705b
1 changed files with 119 additions and 0 deletions
119
N-of-N-Seed-Splitting,-Theory-and-Practice.md
Normal file
119
N-of-N-Seed-Splitting,-Theory-and-Practice.md
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
### Contents
|
||||
+ [N-of-N Seed Splitting: A Theoretical Introduction](#a_nn)
|
||||
+ [Seed Splitting with MMGen](#a_ss)
|
||||
|
||||
#### <a name='a_nn'>N-of-N Seed Splitting: A Theoretical Introduction</a>
|
||||
|
||||
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, *share<sub>1</sub>* is
|
||||
a random value with the same bit length as *seed,* and *share<sub>2</sub>* is
|
||||
the resulting “ciphertext”. Just as the ciphertext reveals nothing about the
|
||||
plaintext in the previous example, *share<sub>2</sub>* reveals nothing about
|
||||
*seed* without knowledge of *share<sub>1</sub>.* And *share<sub>1</sub>,* 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.
|
||||
|
||||
#### <a name='a_ss'>Seed Splitting with MMGen</a>
|
||||
|
||||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue