grin/doc/switch_commitment.md
Yeastplume 5cb8025ddd
[1.1.0] Merge master into 1.1.0 (#2720)
* cleanup legacy "3 dot" check (#2625)

* Allow to peers behind NAT to get up to preferred_max connections (#2543)

Allow to peers behind NAT to get up to preffered_max connections

If peer has only outbound connections it's mot likely behind NAT and we should not stop it from getting more outbound connections

* Reduce usage of unwrap in p2p crate (#2627)

Also change store crate a bit

* Simplify (and fix) output_pos cleanup during chain compaction (#2609)

* expose leaf pos iterator
use it for various things in txhashset when iterating over outputs

* fix

* cleanup

* rebuild output_pos index (and clear it out first) when compacting the chain

* fixup tests

* refactor to match on (output, proof) tuple

* add comments to compact() to explain what is going on.

* get rid of some boxing around the leaf_set iterator

* cleanup

* [docs] Add switch commitment documentation (#2526)

* remove references to no-longer existing switch commitment hash

(as switch commitments were removed in ca8447f3bd
and moved into the blinding factor of the Pedersen Commitment)

* some rewording (points vs curves) and fix of small formatting issues

* Add switch commitment documentation

* [docs] Documents in grin repo had translated in Korean.  (#2604)

*  Start to M/W intro translate in Korean
*  translate in Korean
*  add korean translation  on intro
* table_of_content.md translate in Korean.
*  table_of_content_KR.md finish translate in Korean, start to translate State_KR.md
*  add state_KR.md & commit some translation in State_KR.md
*  WIP stat_KR.md translation
*  add build_KR.md && stratum_KR.md
*  finish translate stratum_KR.md & table_of_content_KR.md
*  rename intro.KR.md to intro_KR.md
*  add intro_KR.md file path each language's  intro.md
*  add Korean translation file path to stratum.md & table_of_contents.md
*  fix difference with grin/master

* Fix TxHashSet file filter for Windows. (#2641)

* Fix TxHashSet file filter for Windows.

* rustfmt

* Updating regexp

* Adding in test case

* Display the current download rate rather than the average when syncing the chain (#2633)

* When syncing the chain, calculate the displayed download speed using the current rate from the most recent iteration, rather than the average download speed from the entire syncing process.

* Replace the explicitly ignored variables in the pattern with an implicit ignore

* remove root = true from editorconfig (#2655)

* Add Medium post to intro (#2654)

Spoke to @yeastplume who agreed it makes sense to add the "Grin Transactions Explained, Step-by-Step" Medium post to intro.md

Open for suggestions on a better location.

* add a new configure item for log_max_files (#2601)

* add a new configure item for log_max_files

* rustfmt

* use a constant instead of multiple 32

* rustfmt

* Fix the build warning of deprecated trim_right_matches (#2662)

* [DOC] state.md, build.md and chain directory documents translate in Korean.  (#2649)

*  add md files for translation.

*  start to translation fast-sync, code_structure. add file build_KR.md, states_KR.md

* add dandelion_KR.md && simulation_KR.md for Korean translation.

*  add md files for translation.

*  start to translation fast-sync, code_structure. add file build_KR.md, states_KR.md

* add dandelion_KR.md && simulation_KR.md for Korean translation.

* remove some useless md files for translation. this is rearrange set up translation order.

*  add dot end of sentence & translate build.md in korean

*  remove fast-sync_KR.md

*  finish build_KR.md translation

*  finish build_KR.md translation

*  finish translation state_KR.md & add phrase in state.md to move other language md file

* translate blocks_and_headers.md && chain_sync.md in Korean

*  add . in chain_sync.md , translation finished in doc/chain dir.

* fix some miss typos

* Api documentation fixes (#2646)

* Fix the API documentation for Chain Validate (v1/chain/validate).  It was documented as a POST, but it is actually a GET request, which can be seen in its handler ChainValidationHandler
* Update the API V1 route list response to include the headers and merkleproof routes.  Also clarify that for the chain/outputs route you must specify either byids or byheight to select outputs.

* refactor(ci): reorganize CI related code (#2658)

Break-down the CI related code into smaller more maintainable pieces.

* Specify grin or nanogrins in API docs where applicable (#2642)

* Set Content-Type in API client (#2680)

* Reduce number of unwraps in chain crate (#2679)

* fix: the restart of state sync doesn't work sometimes (#2687)

* let check_txhashset_needed return true on abnormal case (#2684)

*  Reduce number of unwwaps in api crate  (#2681)

* Reduce number of unwwaps in api crate

* Format use section

* Small QoL improvements for wallet developers (#2651)

* Small changes for wallet devs

* Move create_nonce into Keychain trait

* Replace match by map_err

* Add flag to Slate to skip fee check

* Fix secp dependency

* Remove check_fee flag in Slate

* Add Japanese edition of build.md (#2697)

* catch the panic to avoid peer thread quit early (#2686)

* catch the panic to avoid peer thread quit before taking the chance to ban
* move catch wrapper logic down into the util crate
* log the panic info
* keep txhashset.rs untouched
* remove a warning

* [DOC] dandelion.md, simulation.md ,fast-sync.md and pruning.md documents translate in Korean. (#2678)

* Show response code in API client error message (#2683)

It's hard to investigate what happens when an API client error is
printed out

* Add some better logging for get_outputs_by_id failure states (#2705)

* Switch commitment doc fixes (#2645)

Fix some typos and remove the use of parentheses in a
couple of places to make the reading flow a bit better.

* docs: update/add new README.md badges (#2708)

Replace existing badges with SVG counterparts and add a bunch of new ones.

* Update intro.md (#2702)

Add mention of censoring attack prevented by range proofs

* use sandbox folder for txhashset validation on state sync (#2685)

* use sandbox folder for txhashset validation on state sync

* rustfmt

* use temp directory as the sandbox instead actual db_root txhashset dir

* rustfmt

* move txhashset overwrite to the end of full validation

* fix travis-ci test

* rustfmt

* fix: hashset have 2 folders including txhashset and header

* rustfmt

* 
(1)switch to rebuild_header_mmr instead of copy the sandbox header mmr 
(2)lock txhashset when overwriting and opening and rebuild

* minor improve on sandbox_dir

* add Japanese edition of state.md (#2703)

* Attempt to fix broken TUI locale (#2713)

Can confirm that on the same machine 1.0.2 TUI looks great and is broken on
the current master. Bump of `cursive` version fixed it for me.
Fixes #2676

* clean the header folder in sandbox (#2716)

* forgot to clean the header folder in sandbox in #2685

* Reduce number of unwraps in servers crate (#2707)

It doesn't include stratum server which is sufficiently changed in 1.1
branch and adapters, which is big enough for a separate PR.

* rustfmt

* change version to beta
2019-04-01 11:47:48 +01:00

292 lines
14 KiB
Markdown

# Introduction to Switch Commitments
## General introduction
In cryptography a _Commitment_ (or _commitment scheme_) refers to a concept which can be imagined
like a box with a lock. You can put something into the box (for example a piece of a paper with a
secret number written on it), lock it and give it to another person (or the public).
The other person doesn't know yet what's the secret number in the box, but if you decide to publish
your secret number later in time and want to prove that this really is the secret which you came
up with in the first place (and not a different one) you can prove this simply by giving the
key of the box to the other person.
They can unlock the box, compare the secret within the box with the secret you just published
and can be sure that you didn't change your secret since you locked it. You "**committed**"
to the secret number beforehand, meaning you cannot change it between the time of
commitment and the time of revealing.
## Examples
### Hash Commitment
A simple commitment scheme can be realized with a cryptographic hash function. For example: Alice and Bob
want to play _"Guess my number"_ and Alice comes up with with her really secret number `29` which
Bob has to guess in the game, then before the game starts, Alice calculates:
hash( 29 + r )
and publishes the result to Bob. The `r` is a randomly chosen _Blinding Factor_ which is
needed because otherwise Bob could just try hashing all the possible numbers for the game and
compare the hashes.
When the game is finished, Alice simply needs to publish her secret number `29` and the
blinding factor `r` and Bob can calculate the hash himself and easily verify that Alice
did not change the secret number during the game.
### Pedersen Commitment
Other, more advanced commitment schemes can have additional properties. For example MimbleWimble
and Confidential Transactions (CT) make heavy use of
_[Pedersen Commitments](https://link.springer.com/content/pdf/10.1007/3-540-46766-1_9.pdf)_,
which are _homomorphic_ commitments. Homomorphic in this context means that (speaking in the
"box" metaphor from above) you can take two of these locked boxes (_box1_ and _box2_) and
somehow "_add_" them together, so that you
get a single box as result (which still is locked), and if you open this single box later
(like in the examples before) the secret it contains, is the sum of the secrets
from _box1_ and _box2_.
While this "box" metaphor no longer seems to be reasonable in the real-world this
is perfectly possible using the properties of operations on elliptic curves.
Look into [Introduction to MimbleWimble](intro.md) for further details on Pedersen Commitments
and how they are used in Grin.
## Properties of commitment schemes:
In general for any commitment scheme we can identify two important properties
which can be weaker or stronger, depending on the type of commitment scheme:
- **Hidingness (or Confidentiality):** How good is the commitment scheme protecting the secret
commitment. Or speaking in terms of our example from above: what would an attacker need to
open the box (and learn the secret number) without having the key to unlock it?
- **Bindingness:** Is it possible at all (or how hard would it be) for an attacker to somehow
find a different secret, which would produce the same commitment, so that the attacker could
later open the commitment to a different secret, thus breaking the _binding_ of the
commitment.
### Security of these properties:
For these two properties different security levels can be identified.
The two most important combinations of these are
- **perfectly binding** and **computationally hiding** commitment schemes and
- **computationally binding** and **perfectly hiding** commitment schemes
"_Computationally_" binding or hiding means that the property (bindingness/hidingness)
is secured by the fact that the underlying mathematical problem is too hard to be solved
with existing computing power in reasonable time (i.e. not breakable today as computational
resources are bound in the real world).
"_Perfectly_" binding or hiding means that even with infinite computing power
it would be impossible to break the property (bindingness/hidingness).
### Mutual exclusivity:
It is important to realize that it's **impossible** that any commitment scheme can be
_perfectly binding_ **and** _perfectly hiding_ at the same time. This can be easily shown
with a thought experiment: Imagine an attacker having infinite computing power, he could
simply generate a commitment for all possible values (and blinding factors) until finding a
pair that outputs the same commitment. If we further assume the commitment scheme is
_perfectly binding_ (meaning there cannot be two different values leading to the same
commitment) this uniquely would identify the value within the commitment, thus
breaking the hidingness.
The same is true the other way around. If a commitment scheme is _perfectly hiding_
there must exist several input values resulting in the same commitment (otherwise an
attacker with infinite computing power could just try all possible values as
described above). This concludes that the commitment scheme cannot be _perfectly
binding_.
#### Always a compromise
The key take-away point is this: it's **always a compromise**, you can never have both
properties (_hidingness_ and _bindingness_) with _perfect_ security. If one is _perfectly_
secure then the other can be at most _computationally_ secure
(and the other way around).
### Considerations for cryptocurrencies
Which roles do these properties play in the design of cryptocurrencies?
**Hidingness**:
In privacy oriented cryptocurrencies like Grin, commitment schemes are used to secure
the contents of transactions. The sender commits to an amount of coins he sends, but for
the general public the concrete amount should remain private (protected by the _hidingness_ property of the commitment scheme).
**Bindingness**:
At the same time no transaction creator should ever be able to change his commitment
to a different transaction amount later in time. If this would be possible, an attacker
could spend more coins than previously committed to in an UTXO (unspent transaction
output) and therefore inflate coins out of thin air. Even worse, as the amounts are
hidden, this could go undetected.
So there is a valid interest in having both of these properties always secured and
never be violated.
Even with the intent being that both of these properties will hold for the lifetime
of a cryptocurrency, still a choice has to be made about which commitment scheme to use.
#### A hard choice?
Which one of these two properties needs to be _perfectly_ safe
and for which one it would be sufficient to be _computationally_ safe?
Or in other words: in case of a disaster, if the commitment scheme unexpectedly
gets broken, which one of the two properties should be valued higher?
Economical soundness (no hidden inflation possible) or ensured privacy (privacy will
be preserved)?
This seems like a hard to choice to make.
If we look closer into this we realize that the commitment scheme only needs to be
_perfectly_ binding at the point in time when the scheme actually gets broken. Until
then it will be safe even if it's only _computationally_ binding.
At the same time a privacy-oriented cryptocurrency needs to ensure the _hidingness_
property **forever**. Unlike the _binding_ property, which only is important at the
time when a transaction is created and will not affect past transactions, the _hidingness_
property must be ensured at all times. Otherwise, in the unfortunate case should the
commitment scheme be broken, an attacker could go back in the chain and unblind
past transactions, thus break the privacy property retroactively.
## Properties of Pedersen Commitments
Pedersen Commitments are **computationally binding** and **perfectly hiding** as for a given
commitment to the value `v`: `v*H + r*G` there may exist a pair of different values `r1`
and `v1` such that the sum will be the same. Even if you have infinite computing power
and could try all possible values, you would not be able to tell which one is the original one
(thus _perfectly hiding_).
## Introducing Switch Commitments
So what can be done if the bindingness of the Pedersen Commitment unexpectedly gets broken?
In general a cryptocurrency confronted with a broken commitment scheme could choose to
change the scheme in use, but the problem with this approach would be that it requires to
create new transaction outputs using the new scheme to make funds secure again. This would
require every coin holder to move his coins into new transaction outputs.
If coins are not moved into new outputs, they will not profit from the
security of the new commitment scheme. Also, this has to happen **before** the scheme gets
actually broken in the wild, otherwise the existing UTXOs no longer can be assumed
to contain correct values.
In this situation [_Switch Commitments_](https://eprint.iacr.org/2017/237.pdf) offer a neat
solution. These type of commitments allow changing the properties of the commitments just
by changing the revealing / validating procedure without changing the way commitments
are created. (You "_switch_" to a new validation scheme which is backwards
compatible with commitments created long before the actual "_switch_").
### How does this work in detail
First let's introduce a new commitment scheme: The **ElGamal commitment** scheme is a commitment
scheme similiar to Pedersen Commitments and it's _perfectly binding_ (but only _computationally
hiding_ as we can never have both).
It looks very similar to a Pedersen Commitment, with the addition of a new
element, calculated by multiplying the blinding factor `r` with another generator point `J`:
v*H + r*G , r*J
So if we store the additional field `r*J` and ignore it for now, we can treat it like
Pedersen Commitments, until we decide to also validate the full ElGamal
commitment at some time in future. This is exactly what was implemented in an
[earlier version of Grin](https://github.com/mimblewimble/grin/blob/5a47a1710112153fb38e4406251c9874c366f1c0/core/src/core/transaction.rs#L812),
before mainnet was launched. In detail: the hashed value of `r*J`
(_switch\_commit\_hash_) was added to the transaction output, but this came with
the burden of increasing the size of each output by 32 bytes.
Fortunately, later on the Mimblewimble mailinglist Tim Ruffing came up with a really
[beautiful idea](https://lists.launchpad.net/mimblewimble/msg00479.html)
(initially suggested by Pieter Wuille), which offers the same advantages but doesn't
need this extra storage of an additional element per transaction output:
The idea is the following:
A normal Pedersen commitment looks like this:
v*H + r*G
(`v` is value of the input/output, `r` is a truly random blinding factor, and `H` and `G` are
two generator points on the elliptic curve).
If we adapt this by having `r` not being random itself, but using another random number `r'`
and create the Pedersen Commitment:
v*H + r*G
such that:
r = r' + hash( v*H + r'*G , r'*J )
(using the additional third generation point `J` on the curve) then `r` still is perfectly
valid as a blinding factor, as it's still randomly distributed, but now we see
that the part within the brackets of the hash function (`v*H + r'*G , r'*J`) is an
**ElGamal commitment**.
This neat idea lead to the removal of the switch commitment hash from the outputs in this
(and following) [pull requests](https://github.com/mimblewimble/grin/issues/998) as now it
could be easily included into the Pedersen Commitments.
This is how it is currently implemented in Grin. Pedersen commitments are
used for the Confidential Transaction but instead of choosing the blinding factor `r`
only by random, it is calculated by adding the hash of an ElGamal commitment to a random `r'`
(see here in [main_impl.h#L267](https://github.com/mimblewimble/secp256k1-zkp/blob/73617d0fcc4f51896cce4f9a1a6977a6958297f8/src/modules/commitment/main_impl.h#L267)).
In general switch commitments were first described in the paper
["Switch Commitments: A Safety Switch for Confidential Transactions"](https://eprint.iacr.org/2017/237.pdf)).
The **"switch"** in the name comes from the fact that you can virtually flip a "switch" in
the future and simply by changing the validation procedure you can change the strength of
the bindingness and hidingness property of your commitments and this even works in a
backwards compatible way with commitments created today.
## Conclusion
Grin uses Pedersen Commitments - like other privacy cryptocurrencies do as well - with
the only difference that the random blinding factor `r` is created using the ElGamal
commitment scheme.
This might not seem like a big change on a first look, but it provides an
important safety measure:
Pedersen Commitments are already _perfectly hiding_ so whatever happens, privacy will
never be at risk without requiring any action from users. But in case of a disaster if the
bindingness of the commitment scheme gets broken, then switch commitments can be enabled
(via a soft fork) requiring that all new transactions prove that their commitment is not
breaking the bindingness by validating the full ElGamal commitment.
But in this case users would still have a choice:
- they can decide to continue to create new transactions, even if this might compromise
their privacy (only on their **last** UTXOs) as the ElGamal commitment scheme is
only computationally hiding, but at least they would still have access to their coins
- or users can decide to just leave the money alone, walk away and make no more transactions
(but preserve their privacy, as their old transactions only validated the Pedersen commitment
which is perfectly hiding)
There are many cases where a privacy leak is much more dangerous to one's life than
some cryptocurrency might be worth. But this is a decision that should be left up to
the individual user and switch commitments enable this type of choice.
It should be made clear that this is a safety measure meant to be enabled in case of a
disaster. If advances in computing would put the hardness of the discrete log problem
in question, a lot of other cryptographic systems, including other cryptocurrencies,
will be in urgent need of updating their primitives to a future-proof system. The switch
commitments just provide an additional layer of security if the bindingness of Pedersen
commitments ever breaks unexpectedly.