Update intro.md (#2975)

* Update intro.md

Significant clarifications, especially in the paragraph where excess value is introduced and the section about kernel offsets.

* fix and clarify section about kernel offsets

"Splitting" the blinding factor into *k1* and *k2* is unnecessarily confusing I think. The excess and the offset are really two arbitrary numbers without any mathematical relation to each other. I think I rephrased the section as well as I could without sacrificing any correctness for the sake of simplicity (which I think would be more confusing than helpful).

* do the same fixes for the Swedish version

* small fix regarding aggregation

Transactions are not aggregated by non-mining nodes as well. Removed the part about miners.

Co-authored-by: Quentin Le Sceller <q.lesceller@gmail.com>
This commit is contained in:
Ramin Soltanzadeh 2020-02-04 21:50:06 +01:00 committed by GitHub
parent 6c528654df
commit a41965e024
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 90 deletions

View file

@ -103,9 +103,9 @@ Verifying this property on every transaction allows the protocol to verify that
transaction doesn't create money out of thin air, without knowing what the actual
values are. However, there are a finite number of usable values (transaction amounts) and one
could try every single
one of them to guess the value of your transaction. In addition, knowing v1 (from
one of them to guess the value of the transaction. In addition, knowing *v1* (from
a previous transaction for example) and the resulting `v1*H` reveals all outputs with
value v1 across the blockchain. For these reasons, we introduce a second point _G_ on the same elliptic curve
value *v1* across the blockchain. For these reasons, we introduce a second point _G_ on the same elliptic curve
(practically _G_ is just another generator point on the same curve group as _H_) and
a private key _r_ used as a *blinding factor*.
@ -126,8 +126,8 @@ Curve Cryptography. `r*G + v*H` is called a _Pedersen Commitment_.
As an example, let's assume we want to build a transaction with two inputs and one
output. We have (ignoring fees):
* `vi1` and `vi2` as input values.
* `vo3` as output value.
* *vi1* and *vi2* as input values.
* *vo3* as output value.
Such that:
@ -192,25 +192,15 @@ She picks 113 say, and what ends up on the blockchain is:
Y - Xi = (113*G + 3*H) - (28*G + 3*H) = 85*G + 0*H
Now the transaction no longer sums to zero and we have an _excess value_ on _G_
(85), which is the result of the summation of all blinding factors. But because `85*G` is
a valid public key on the elliptic curve _C_, with private key 85,
for any x and y, only if `y = 0` is `x*G + y*H` a valid public key on the elliptic curve
using generator point _G_.
Now the transaction no longer sums to zero and we have an _excess value_ (85), which is the result of the summation of all blinding factors. Because `85*G` is
a valid public key for the generator point _G_ the input and output values must sum to zero and the transaction is thus valid, since `x*G + y*H` is a valid public key for generator point _G_ if and only if `y = 0`.
So all the protocol needs to verify is that (`Y - Xi`) is a valid public key on the curve
and that the transacting parties collectively know the private key `x` (85 in our transaction with
Carol) of this public key. If they can prove that they know the private key to `x*G + y*H` using
generator point _G_ then this proves that `y` must be `0` (meaning above that the sum of all
inputs and outputs equals `0`).
So all the protocol needs to verify is that (`Y - Xi`) is a valid public key for generator point _G_
and that the transacting parties collectively can produce its private key (85 in the above example). The simplest way to do so is to require a signature built with the excess value (85),
which then ensures that:
The simplest way to do so is to require a signature built with the excess value (85),
which then validates that:
* The transacting parties collectively know the private key (the excess value 85), and
* The sum of the transaction outputs, minus the inputs, sum to a zero value
(because only a valid public key, matching the private key, will check against
the signature).
* The transacting parties collectively can produce the private key (the excess value)
* The sum of the outputs minus the inputs are zero (because only a valid public key will check against the signature).
This signature, attached to every transaction, together with some additional data (like mining
fees), is called a _transaction kernel_ and is checked by all validators.
@ -245,8 +235,7 @@ introduction of negative amounts would be extremely problematic as one could
create new funds in every transaction.
For example, one could create a transaction with an input of 2 and outputs of 5
and -3 and still obtain a well-balanced transaction, following the definition in
the previous sections. This can't be easily detected because even if _x_ is
and -3 and still obtain a well-balanced transaction. This can't be easily detected because even if _x_ is
negative, the corresponding point `x*H` on the curve looks like any other.
To solve this problem, Mimblewimble leverages another cryptographic concept (also
@ -256,14 +245,20 @@ the number. We won't elaborate on the range proof, but you just need to know
that for any `r*G + v*H` we can build a proof that will show that _v_ is greater than
zero and does not overflow.
It's also important to note that in order to create a valid range proof from the example above, both of the values 113 and 28 used in creating and signing for the excess value must be known. The reason for this, as well as a more detailed description of range proofs are further detailed in the [range proof paper](https://eprint.iacr.org/2017/1066.pdf).
The requirement to know both values to generate valid rangeproofs is an important feature since it prevents a censoring attack where a third party could lock up UTXOs without knowing their private key by creating a transaction from
It's also important to note that range proofs for both the blinding factor and the values are needed. The reason for this
is that it prevents a censoring attack where a third party would be able to lock UTXOs without knowing their private keys
by creating a transaction such as the following:
Carol's UTXO: 113*G + 2*H
Attacker's output: (113 + 99)*G + 2*H
Carol's UTXO: 113*G + 2*H
Attacker's output: (113 + 99)*G + 2*H
which can be signed by the attacker since Carols private key of 113 cancels due to the adversarial choice of keys. The new output could only be spent by both the attacker and Carol together. However, while the attacker can provide a valid signature for the transaction, it is impossible to create a valid rangeproof for the new output invalidating this attack.
which can be signed by the attacker because Carol's blinding factor cancels out in the equation `Y - Xi`:
Y - Xi = ((113 + 99)*G + 2*H) - (113*G + 2*H) = 99*G
This output (`(113 + 99)*G + 2*H`) requires that both the numbers 113 and 99 are known in order to be spent; the attacker
would thus have successfully locked Carol's UTXO. The requirement for a range proof for the blinding factor prevents this
because the attacker doesn't know the number 113 and thus neither (113 + 99). A more detailed description of range proofs is further detailed in the [range proof paper](https://eprint.iacr.org/2017/1066.pdf).
#### Putting It All Together
@ -273,14 +268,14 @@ A Mimblewimble transaction includes the following:
* A set of new outputs that include:
* A value and a blinding factor (which is just a new private key) multiplied on
a curve and summed to be `r*G + v*H`.
* A range proof that shows that v is non-negative.
* An explicit transaction fee, in clear.
* A signature, computed by taking the excess blinding value (the sum of all
outputs plus the fee, minus the inputs) and using it as a private key.
* A range proof that among other things shows that *v* is non-negative.
* An transaction fee in cleartext.
* A signature whose private key is computed by taking the excess value (the sum of all
output values plus the fee, minus the input values).
### Blocks and Chain State
We've explained above how Mimblewimble transactions can provide
We explained above how Mimblewimble transactions can provide
strong anonymity guarantees while maintaining the properties required for a valid
blockchain, i.e., a transaction does not create money and proof of ownership
is established through private keys.
@ -291,30 +286,28 @@ concept: _cut-through_. With this addition, a Mimblewimble chain gains:
* Extremely good scalability, as the great majority of transaction data can be
eliminated over time, without compromising security.
* Further anonymity by mixing and removing transaction data.
* And the ability for new nodes to sync up with the rest of the network very
efficiently.
#### Transaction Aggregation
Recall that a transaction consists of the following -
Recall that a transaction consists of the following:
* a set of inputs that reference and spent a set of previous outputs
* a set of new outputs (Pedersen commitments)
* a transaction kernel, consisting of
* kernel excess (Pedersen commitment to zero)
* transaction signature (using kernel excess as public key)
* a set of new outputs
* a transaction kernel consisting of:
* kernel excess (the public key of the excess value)
* transaction signature whose public key is the kernel excess
A tx is signed and the signature included in a _transaction kernel_. The signature is generated using the _kernel excess_ as a public key proving that the transaction sums to 0.
A transaction is validated by determining that the kernel excess is a valid public key:
(42*G + 1*H) + (99*G + 2*H) - (113*G + 3*H) = 28*G + 0*H
The public key in this example being `28*G`.
The public key in this example is `28*G`.
We can say the following is true for any valid transaction (ignoring fees for simplicity) -
We can say the following is true for any valid transaction (ignoring fees for simplicity):
sum(outputs) - sum(inputs) = kernel_excess
The same holds true for blocks themselves once we realize a block is simply a set of aggregated inputs, outputs and transaction kernels. We can sum the tx outputs, subtract the sum of the tx inputs and compare the resulting Pedersen commitment to the sum of the kernel excesses -
The same holds true for blocks themselves once we realize a block is simply a set of aggregated inputs, outputs and transaction kernels. We can sum the outputs, subtract the inputs from it and equating the resulting Pedersen commitment to the sum of the kernel excesses:
sum(outputs) - sum(inputs) = sum(kernel_excess)
@ -322,35 +315,37 @@ Simplifying slightly, (again ignoring transaction fees) we can say that Mimblewi
##### Kernel Offsets
There is a subtle problem with Mimblewimble blocks and transactions as described above. It is possible (and in some cases trivial) to reconstruct the constituent transactions in a block. This is clearly bad for privacy. This is the "subset" problem - given a set of inputs, outputs and transaction kernels a subset of these will recombine to reconstruct a valid transaction.
There is a subtle problem with Mimblewimble blocks and transactions as described above. It is possible (and in some cases trivial) to reconstruct the constituent transactions in a block. This is clearly bad for privacy. This is the "subset" problem: given a set of inputs, outputs, and transaction kernels a subset of these will recombine to reconstruct a valid transaction.
For example, given the following two transactions -
Consider the following two transactions:
(in1, in2) -> (out1), (kern1)
(in3) -> (out2), (kern2)
We can aggregate them into the following block (or aggregate transaction) -
We can aggregate them into the following block (or aggregate transaction):
(in1, in2, in3) -> (out1, out2), (kern1, kern2)
It is trivially easy to try all possible permutations to recover one of the transactions (where it sums successfully to zero) -
It is trivially easy to try all possible permutations to recover one of the transactions (where it successfully sums to zero):
(in1, in2) -> (out1), (kern1)
We also know that everything remaining can be used to reconstruct the other valid transaction -
We also know that everything remaining can be used to reconstruct the other valid transaction:
(in3) -> (out2), (kern2)
To mitigate this we include a _kernel offset_ with every transaction kernel. This is a blinding factor (private key) that needs to be added back to the kernel excess to verify the commitments sum to zero -
Remember that the kernel excess `r*G` simply is the public key of the excess value *r*. To mitigate this we redefine the kernel excess from `r*G` to `(r-kernel_offset)*G` and distribute the _kernel offset_ to be included with every transaction kernel. The kernel offset is thus a blinding factor that needs to be added to the excess value to ensure the commitments sum to zero:
sum(outputs) - sum(inputs) = kernel_excess + kernel_offset
sum(outputs) - sum(inputs) = r*G = (r-kernel_offset)*G + kernel_offset*G
When we aggregate transactions in a block we store a _single_ aggregate offset in the block header. And now we have a single offset that cannot be decomposed into the individual transaction kernel offsets and the transactions can no longer be reconstructed -
or alternatively
sum(outputs) - sum(inputs) = sum(kernel_excess) + kernel_offset
sum(outputs) - sum(inputs) = kernel_excess + kernel_offset*G
For a commitment `r*G + 0*H` with the offset `a`, the transaction is signed with `(r-a)` and *a* is published so that `r*G` can be calculated in order to verify the validity of the transaction. During block construction all kernel offsets are summed to generate a _single_ aggregate kernel offset to cover the whole block. The kernel offset for any individual transaction is then unrecoverable and the subset problem is solved.
sum(outputs) - sum(inputs) = sum(kernel_excess) + kernel_offset*G
We "split" the key `k` into `k1+k2` during transaction construction. For a transaction kernel `(k1+k2)*G` we publish `k1*G` (the excess) and `k2` (the offset) and sign the transaction with `k1*G` as before.
During block construction we can simply sum the `k2` offsets to generate a single aggregate `k2` offset to cover all transactions in the block. The `k2` offset for any individual transaction is unrecoverable.
#### Cut-through
@ -371,14 +366,14 @@ in a previous block is marked with a lower-case x.
We notice the two following properties:
* Within this block, some outputs are directly spent by included inputs (I3
spends O2 and I4 spends O3).
* The structure of each transaction does not actually matter. As all transactions
* Within this block, some outputs are directly spent by following inputs (*I3*
spends *O2* and *I4* spends *O3*).
* The structure of each transaction does not actually matter. Since all transactions
individually sum to zero, the sum of all transaction inputs and outputs must be zero.
Similarly to a transaction, all that needs to be checked in a block is that ownership
has been proven (which comes from _transaction kernels_) and that the whole block did
not add any money supply (other than what's allowed by the coinbase).
has been proven (which comes from the _transaction kernels_) and that the whole block did
not create any coins (other than what's allowed as the mining reward).
Therefore, matching inputs and outputs can be eliminated, as their contribution to the overall
sum cancels out. Which leads to the following, much more compact block:
@ -387,8 +382,7 @@ sum cancels out. Which leads to the following, much more compact block:
| O5
Note that all transaction structure has been eliminated and the order of inputs and
outputs does not matter anymore. However, the sum of all outputs in this block,
minus the inputs, is still guaranteed to be zero.
outputs does not matter anymore. However, the sum of all inputs and outputs is still guaranteed to be zero.
A block is simply built from:
@ -397,7 +391,7 @@ A block is simply built from:
* The list of outputs remaining after cut-through.
* A single kernel offset to cover the full block.
* The transaction kernels containing, for each transaction:
* The public key `r*G` obtained from the summation of all the commitments.
* The public key `r*G` obtained from the summation of all inputs and outputs.
* The signatures generated using the excess value.
* The mining fee.
@ -405,22 +399,21 @@ When structured this way, a Mimblewimble block offers extremely good privacy
guarantees:
* Intermediate (cut-through) transactions will be represented only by their transaction kernels.
* All outputs look the same: just very large numbers that are impossible to
differentiate from one another. If one wanted to exclude some outputs, they'd have
* All outputs look the same: very large numbers that are impossible to
meaningfully differentiate from one another. If someone wants to exclude a specific output, they'd have
to exclude all.
* All transaction structure has been removed, making it impossible to tell which output
was matched with each input.
* All transaction structure has been removed, making it impossible to tell which inputs and outputs match.
And yet, it all still validates!
#### Cut-through All The Way
Going back to the previous example block, outputs x1 and x2, spent by I1 and
I2, must have appeared previously in the blockchain. So after the addition of
this block, those outputs as well as I1 and I2 can also be removed from the
overall chain, as they do not contribute to the overall sum.
Going back to the previous example block, outputs *x1* and *x2*, spent by *I1* and
*I2*, must have appeared previously in the blockchain. So after the addition of
this block, those outputs as well as *I1* and *I2* can also be removed from the
blockchain as they now are intermediate transactions.
Generalizing, we conclude that the chain state (excluding headers) at any point
We conclude that the chain state (excluding headers) at any point
in time can be summarized by just these pieces of information:
1. The total amount of coins created by mining in the chain.
@ -428,19 +421,19 @@ in time can be summarized by just these pieces of information:
1. The transactions kernels for each transaction.
The first piece of information can be deduced just using the block
height (its distance from the genesis block). And both the unspent outputs and the
transaction kernels are extremely compact. This has 2 important consequences:
height.
* The state a given node in a Mimblewimble blockchain needs to maintain is very
small (on the order of a few gigabytes for a bitcoin-sized blockchain, and
Both the UTXOs and the
transaction kernels are extremely compact. This has two important consequences:
* The blockchain a node needs to maintain is very small (on the
order of a few gigabytes for a bitcoin-sized blockchain, and
potentially optimizable to a few hundreds of megabytes).
* When a new node joins a network building up a Mimblewimble chain, the amount of
information that needs to be transferred is also very small.
* When a new node joins the network the amount of
information that needs to be transferred is very small.
In addition, the complete set of unspent outputs cannot be tampered with, even
only by adding or removing an output. Doing so would cause the summation of all
blinding factors in the transaction kernels to differ from the summation of blinding
factors in the outputs.
In addition, the UTXO set cannot be tampered with. Adding or removing even
one input or output would change the sum of the transactions to be something other than zero.
### Conclusion

View file

@ -300,13 +300,17 @@ Vi vet också att allt som kvarstår kan användas för att rekonstruera den and
(input3) -> (output2), (kärna2)
För att mildra detta inkluderar vi ett _kärn-offset_ med varje transaktionskärna. Detta är en publik nyckel som måste
tilläggas kärnöverskottet för att balansera ekvationen:
Kom ihåg att kärnöverskottet `r*G` helt enkelt är den publika nyckeln till överskottsbeloppet *r*. För att lösa detta problem omdefinierar vi kärnöverskottet från `r*G` till `(r-kärn_offset)*G` och distribuerar detta *kärn-offset* för att inkluderas i varje transktionskärna. Detta kärn-offset är således en förblindningsfaktor som måste tilläggas överskottsbeloopet för att ekvationen ska gå ihop:
(summan av outputs) - (summan av inputs) = kärnöverskott + kärn-offset
(summan av outputs) - (summan av inputs) = r*G = (r-kärn_offset)*G + kärn_offset*G
Vi "separerar" nyckeln `k` till `k1 + k2` under transaktionsbyggandet. Vi signerar transaktionen med `k1` och publicerar `k2` för att skapa vårt kärn-offset (`k2*G`). Vid block-konstruktionen
kan alla kärn-offset summeras för att generera ett aggregat-offset för alla transaktioner i blocket. Kärn-offset för individuella transaktioner blir därmed omöjliga att härleda från ett färdigt block och delmängdsproblemet är löst.
eller alternativt
(summan av outputs) - (summan av inputs) = kärnöverskott + kärn_offset*G
För ett commitment `r*G + 0*H` med kärn-offset *a*, signeras transaktionen med `(r-a)` och *a* publiceras så att `r*G` kan beräknas för att kontrollera att transaktionen är giltig. Vid block-konstruktionen summeras alla kärn-offsets till ett enstaka sammanlagt offset som täcker hela blocket. Kärn-offsetet för en individuell transaktion blir därmed omöjlig att härleda och delmängdsproblemet är löst.
(summan av outputs) - (summan av inputs) = (summan av kärnöverskott) + kärn_offset*G
#### Genomskärning