Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EIP-0011: Distributed Signatures #8

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
140 changes: 140 additions & 0 deletions eip-0011.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
EIP-11: Distributed Signatures
==============================

* Author: kushti, scalahub
* Status: Proposed
* Created: 07-Oct-2019
* License: CC0
* Forking: not needed

This EIP defines how to implement distributed signatures on top of the Ergo Platform.


Motivating Examples
-------------------

Alice, Bob and Carol have a joint business and need joint control over business funds. They decide that a 2-out-of-3 quorum is enough to spend the joint funds, so that there is no problem if one of them can not sign because of an illness or a vacation. Thus, they store such funds in boxes protected by 2-out-of-3 threshold signature.

Please note that unlike multi-signatures in Bitcoin, threshold signatures in Ergo preserve zero-knowledge. This leads to interesting applications where actual signers must be hidden but the signing ring is not. For example, it could be desirable to show that union paid to a lawyer, but it is better to hide who approved that spending.

Sigma Protocols
---------------

A Sigma-protocol is a three-step protocol between a prover and a verifier jointly sharing a public "statement" *y*, where the prover wants to prove knowledge of some secret *x* such that *(x, y)* form some relation, such as being a (private, public) keypair. We call this "proving the statement" *y*. First, the prover generates (secret) randomness and sends to the verifier, a commitment *a* to the secret. The verifier stores the commitment and sends a random challenge *e* to the prover. The prover generates a response *z* based on the randomness plus the challenge and sends it to the verifier. The verifier checks the tuple *(a,e,z)* and accepts if it is valid.

A Sigma-protocol can be converted to a signature scheme by using Fiat-Shamir transformation. Basically, using commitment *a*, prover can get challenge as *e = hash(a)* (note that this is the so-called "Weak" Fiat Shamir transform, while Ergo uses the Strong Fiat-Shamir transform, where *e = hash(y || a)*, and *y* is the statement (public key) that the prover is proving.

Sigma protocols also allow simulation of proofs, AND / OR / threshold conjectures. Good introductions can be found in Chapter 6 of the "Efficient Secure Two-Party Protocols: Techniques and Constructions" book by Lindell and Hazay, and also in the tutorial by Ivan Damgard: https://cs.au.dk/~ivan/Sigma.pdf.

For details on how proving and verification of arbitrary statements is done in ErgoTree (after reduction), see Appendix A in the ErgoScript whitepaper: https://ergoplatform.org/docs/ErgoScript.pdf.

For instance, a 2-out-of-3 Sigma proof consists of 3 arbitrary statements (*y_1*, *y_2*, *y_3*), and the prover proves any 2 of them without revealing which ones are actually proven. Let *i, j, k* be in {1, 2, 3} such that prover knows secrets of *y_i, y_j* but not of *y_k*.
The prover simulates a proof of *y_k* to generate an accepting transcript *(a_k, e_k, z_k)*. He then generates *a_i, a_j* as a proper prover and sends (*a_1, a_2, a_3*) to the verifier. The verifer chooses a challenge *s* and sends back to the prover.
The prover then computes *e_i, e_j* such that *(e_1, e_2, e_3)* form consistent 2-out-of-3 shares of *s* in an ideal secret sharing scheme. Finally the prover computes *z_i, z_j* using the proper procedure. The tuple *(e_1, e_2, e_3, z_1, z_2, z_3)* is sent to the verifier. The verifier accepts if *(a_1, e_1, z_1), (a_2, e_2, z_2), (a_3, e_3, z_3)* are accepting transcripts and *(e_1, e_2, e_3)* form consistent 2-out-of-3 shares of *s*. For details refer to the paper [CDS94]( https://www.win.tue.nl/~berry/papers/crypto94.pdf). The non-interactive variant computes *s = hash(y_1 || y_2 || y_3 || a_1 || a_2 || a_3)*.


Signing Procedure
-----------------

First, signing quorum should be decided. For example, Alice and Bob may decide to sign a transaction. Other parties (Carol in this case) will be simulated. The procedure requires an off-chain interaction between Alice and Bob but they don't have to share secrets.

Then every real signer needs to generate commitments. In our scenario this means that Alice, for example, will send her commitment *a_A* to Bob. On getting Alice's commitment, Bob produces a partial threshold signature as follows. First he simulates Carol to get tuples *(a_C, e_C, z_C)* and generates his commitment *a_B* properly. Then he uses *(a_A, a_B, a_C)* to compute *s* as described above. In the final partial signature, his tuple *(a_B, e_B, z_B)* is proper, Carol's tuple *(a_C, e_C, z_C)* is properly simulated as well, but for Alice's part nothing is computed. Thus, the whole threshold signature is invalid. Bob needs Alice to complete the signature.

Bob sends *(a_B, e_B, z_B, a_C, e_C, z_C)* to Alice, using which she can now provide a valid signature.

In the general case, signing procedure is as follows:

* First, the needed quorum of real participants is to be decided. Please note that in case of 2-out-3 signature, there are just 2 and only 2 signers needed (a third one will be simulated anyway by the prover).
* Second, real participants generate commitments. In the simplest case, they can be sent to one of the signers.
* One signer is producing an invalid signature and sends simulated commitments and his commitment and response to others.
* Others produce proper responses and send them to the chosen signer (or broadcast)
* Now the signer can assemble a valid signature.

The most complex example at the moment of writing this document is 4-out-of-8 signature and it can be found in DistributedSigSpecification.scala of https://github.com/ScorexFoundation/sigmastate-interpreter/pull/412 .


Data Packets
------------

JSON documents are used for exchanging data needed for distributed signature generation.

JSON encoding transaction is already done in Ergo Platform reference client API, please check "UnsignedErgoTransaction"
in [openapi.yaml](https://github.com/ergoplatform/ergo/blob/master/src/main/resources/api/openapi.yaml).

A commitment (a) is about one secp256k1 element in case of prove-dlog (Schnorr signature) protocol, and two elements in
case of prove-Diffie-Hellman-tuple protocol. Element encoded as Base16-encoded x-coordinate with a sign byte
(of the y-coordinate) prepended, see ASN.1 for details (the only difference is that INF point encoded as 33 zero bytes).

A challenge (e) is encoded as Base-16 encoded 256-bits (32-bytes) array.

Response (z) is 256-bits number encoded with Base16.

A public key is encoded as one secp256k1 element in case of prove-dlog, four elements in case of
prove-diffie-hellman-tuple:

{
"hint": "commitment",
"index": 0,
"type": "dlog",
"real": true,
"pk": "03a73c66970f14fc6450c6ab1a167cb4ba3baa64b20f731e22ec6840c70d27ef1c",
"commitment": "0253db866791af521ba4ab009509b6db89d272d9461636ee65eaa3e316884b21a4"
}

or

{
"hint": "commitment",
"type": "dht",
"real": false,
"pk": [
"03a73c66970f14fc6450c6ab1a167cb4ba3baa64b20f731e22ec6840c70d27ef1c",
"03a73c66970f14fc6450c6ab1a167cb4ba3baa64b20f731e22ec6840c70d27ef1c",
"03a73c66970f14fc6450c6ab1a167cb4ba3baa64b20f731e22ec6840c70d27ef1c",
"03a73c66970f14fc6450c6ab1a167cb4ba3baa64b20f731e22ec6840c70d27ef1c"
],
"commitment": [
"0253db866791af521ba4ab009509b6db89d272d9461636ee65eaa3e316884b21a4",
"0253db866791af521ba4ab009509b6db89d272d9461636ee65eaa3e316884b21a4"
]
}

, where "index" is input index a hint is provided for. A partial signature can be encoded then as

{
"hint": "partial-sig",
"index": 0,
"type": "dlog",
"real": true,
"pk": "03a73c66970f14fc6450c6ab1a167cb4ba3baa64b20f731e22ec6840c70d27ef1c",
"commitment": "0253db866791af521ba4ab009509b6db89d272d9461636ee65eaa3e316884b21a4",
"challenge": "0253db866791af521ba4ab009509b6db89d272d9461636ee65eaa3e316884b21a4",
"response": "0253db866791af521ba4ab009509b6db89d272d9461636ee65eaa3e316884b21a4"
}

and similarly for dht.

Then we have two possible clients, stateful, which do store locally unsigned transactions and so can use transaction id
in messages, and stateless, which do not store any information. Then in the stateless setting
(reference protocol client will likely support only initially) signing request would be like current
signing request for "/wallet/transaction/sign" API method. A signature and so transaction generated could be invalid
(see "Signing Procedure" section). It is up to external utilities (or manual efforts) to gather needed hints for the
prover.


Prover Implementation
---------------------

Implementation of the prover supporting hints from outside allowing for distributed signatures done
[in this PR in the sigmastate-interpreter repository](https://github.com/ScorexFoundation/sigmastate-interpreter/pull/412).

Support in the Reference Protocol Client
----------------------------------------

[This PR](https://github.com/ergoplatform/ergo/pull/1118).

Limitations
-----------

Please note that while threshold signatures preserve zero-knowledge (e.g. in case of 2-out-of-3 threshold signature it is
known that two parties of out three at least signed an input, but not known who are these parties exactly) for a blockchain observer, participants of the signing group know who was involved in the signing process. Secrecy within the group can be achieved via MPC protocols.