diff --git a/eip-0011.md b/eip-0011.md new file mode 100644 index 00000000..52f49e86 --- /dev/null +++ b/eip-0011.md @@ -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.