ing-bank / threshold-signatures

Threshold Signature Scheme for ECDSA
MIT License
201 stars 41 forks source link
bitcoin-transaction cryptocurrency cryptography ecdsa ethereum homomorphic-encryption rust secure-multi-party-computation zero-knowledge-proofs

Multiparty threshold ECDSA scheme

Warning

This repository is no longer maintained. There are known security issues as pointed in this article. No updates or fixes actively being pursued. The library was implemented for research purposes and not used in production within the organization. ING strongly advises that you do NOT use this library in your code and use this code ONLY as a reference for research.

Introduction

The project contains the implementation of the multiparty threshold signature scheme constructed by Rosario Gennaro and Steven Goldfeder [1]. The scheme consists of three algorithms performed in a distributed context: a key generation with N parties, an arbitrary message signing with a subgroup of [(t+1) of N] parties holding the key, and the key resharing with (t+1) parties resulting in a new group of M players holding new shares of the same private signing key.

This README file focuses on sharing detailed technical information about the library. Check our whitepaper [5] for theoretical backgrounds.

The library has been reviewed by Kudelski Security company, see The security risk assessment report.

Motivation

Elliptic curve digital signature algorithm (ECDSA) is used extensively for crypto-currencies such as Bitcoin and Ethereum to sign transactions.
Multiparty threshold signing adds a possibility to create crypto-currency wallets that are controlled by multiple parties. Transactions which originate from these wallets require collaborative work to sign. Threshold signing produces standard signature output, and it preserves the privacy of signers by not disclosing their identities, unlike multi-signature does. The algorithm used in this product eliminates a central dealer( the party which generates the full key and distributes shards of it to parties).

As the MPC TS technology has become increasingly popular in the last 2 years, there are quite a few open-source implementations. The detailed review of them can be found in [6]. Our version improves existing solutions by addition of several key features:

We also designed the library with the separation of concern (SoC) principle in mind. This library encompasses the complete protocol logic that includes party identity management, error reporting, and timeout detection. These activities are not delegated to the application, unlike in some other implementations. Only a basic network layer has to be added to wrap the library into a standalone application. This layer has to maintain the mapping between party id and corresponding OS-level connector (e.g. socket), and to parse the destination attribute of any message. In addition to that, peer-directed messages have to be encrypted and decrypted. The library code does not contain an encryption schema for secret messages, as that would restrict schema choices and add schema's key management duties.

The set of responsibilities of the library layer is determined to the following:

We also paid attention to the usage of :

Signature schema

The ECDSA consist of 3 algorithms ([1], 2.1, 2.5):

Key generation

The initial partial key is sampled from randomness by each party, so that the resulting public key is the product of partial public keys and the resulting private key is the sum of partial private keys.

Private keys are shared with Shamir's secret sharing schema [2] where its signing threshold becomes the attribute of the resulting key. Additional non-malleable commitment to a partial public key is shared to prevent the classic attack on [2].

Since the signing algorithm uses additive homomorphic encryption schema (AHE) [3], the setup of range proofs [4] is required ([1] addendum A) at the key generation stage.

Signing

The ECDSA requires a random coefficient that needs to be multiplied by private key during the signing. The result of multiplication has to be shared additively in case of a multi-party setup. To get an additive sharing of the multiple, it is sufficient to get the additive sharing of each individual term, but each term contains secrets of two different parties. To overcome the privacy problem the algorithm uses multiplication-to-addition (MtA) 2-party protocol ([1], 3). The MtA protocol uses the AHE scheme [3] with its public key shared before signing.

In addition to that, several zero-knowledge proofs are generated at the last stages of the signing protocol to prevent the algorithm from producing a wrong signature ([1], 4.2, phase 5). Every party receives the complete signature at the end.

Verification

The protocol outputs the standard signature which is publicly verifiable. The verification does not require interactions with parties.

Execution model

The library implements the dedicated state machine to run protocols. Each protocol is a sequence of phases, and each phase consists of three steps: optional message sending, waiting for input, and consuming the collected input. The consumption results in either transitioning to another phase or stopping the machine and returning either the final result or a collection of error codes. The machine may also be stopped by reaching a timeout, or it can be aborted by sending a special message to it. The aborted machine returns no result.

Due to the asynchronous nature of protocols the state machine has a buffer for messages which could be awaited by the next phases of the protocol but arrived too early.

The state machine code can be executed concurrently by independent threads. Every phase of each protocol has a local context that is not shared with other phases and instances of the protocol. As a consequence, the MPC application can run multiple sessions of key generation and sign simultaneously. Note that the library itself does not handle sessions, it is the main application that has to run multiple state machines and route network streams to/from these machines accordingly.

Usage

Library structure

The library consist of three main modules:

Examples

Key generation

The example is taken from the test submodule of keygen module with some minor details omitted.

The input for the protocol contains:

The first phase of the protocol is created by calling Phase1::new() method, which takes all the parameters above.

The state machine is created next, with the following input:

Two distinct versions of the state machine in this library support two types for stream/sink:

   // set protocol parameters
   let params = Parameters {
                share_count: 3,
                threshold: 1,
            };
   // collect list of parties
   let parties : Vec<PartyIndex> = ...
   // determine the party index of this node  
   let own_party_index = ... 
   // create initial random keys
   let init_keys = InitialKeys::random();
   let init_pub_keys = InitialPublicKeys::from(&init_keys);
   // create some wallet (a peristence provider) and the secret loader
   // secret loader acts as proxy fetching secret keys from the wallet 
   // [see the example in ecds::keygen::test module]      
   let shared_wallet = MyWallet::new(init_keys);    
   let secret_loader = SecretKeyLoaderImpl::new(&shared_wallet, own_party_index);

   let start_state = Box::new(Phase1::new(
                    &params,
                    init_pub_keys,
                    range_proof_setup,
                    parties.as_slice(),
                    own_party_index,
                    Arc::new(Box::new(secret_loader)),
                    None,
                )?);

   // Channel to pick messages the state machine sends
   let (state_machine_sink, state_machine_stream) = mpsc::unbounded();
   // Channel to feed the machine
   let (protocol_sink, protocol_stream) = mpsc::unbounded();
   let state_machine = StateMachine::new(start_phase, protocol_stream, state_machine_sink);

   ...

    tokio::spawn(async move {
        let result = match state_machine.execute().await.transpose() {
            Ok(Some(fs)) => Outcome::Keygen(Ok(fs)),
            Ok(None) => {
               Outcome::Keygen(Err(ErrorState::new(vec![KeygenError::GeneralError {
                        desc: "Keygen did not produce a result".to_string(),
                    }])))
                }
            Err(err) => Outcome::Keygen(Err(err)),
            };
            ...
Signing

The input of the protocol contains:

The sequence of actions for signing is similar to keygen: first, the phase object is created, and then the state machine is. Similarly to the key generation protocol, state machine requires first phase and communication channels.

Note that the signing protocol expects a message to be hashed outside of this library (see module documentation in signature.rs).

     let mut hasher = Sha256::new();
     hasher.input("The message we sign");
     let msg_hash = ECScalar::from(&BigInt::from(hasher.result().as_slice()));

     let start_phase: BoxedState<InMsg, OutMsg, MachineResult> = Box::new(Phase1::new(
                    &msg_hash,
                    multi_party_shared_info,
                    &quorum.parties,
                ));
                let mut main_machine =
                    StateMachine::new(start_phase, to_main_machine, from_main_machine);
                let machine_result = main_machine.execute().await;
                let outcome = match machine_result.transpose() {
                    Ok(Some(fs)) => Outcome::Signature(Ok(fs)),
                    Ok(None) => {
                        Outcome::Signature(Err(ErrorState::new(vec![SigningError::GeneralError {
                            desc: "Signing algorithm did not produce a result".to_string(),
                        }])))
                    }
                    Err(err) => Outcome::Signature(Err(err)),
                };

Building the documentation

The library uses LaTex mathematical symbols in the documentation so that embedded docs have to be built with predefined HTML header (included into the project):

cargo rustdoc  --  --html-in-header katex.html --document-private-items

The nightly build of rustdoc is not required: the code is documented using traditional reference link style.

Using examples

The simulator of the key generation protocol

The complete result of the protocol can be obtained in JSON format by running the command:

cargo run --example keygen min_number_of_signers total_number_of_signers output_file_name_prefix [--use-range-proofs]

The run results in creating #total_number_of_signers# files containing MultiPartyInfo structure serialized into JSON. File names can be tweaked by output_file_name_prefix.

Note: the signing protocol is proven to be insecure when used without range proofs. The keygen example quits with the error if the range proof setup option is not used)

The generator of zero knowledge range proof setup

Recall that the ZKRP setup requires safe primes, for which the algorithm is not particularly fast. If the generation of new ZKRP setups for each new key has to be avoided, then setups have to be pre-computed.
The following command generates as many as n setups and prints them to the standard output:

cargo run --release --example zkp-setup n >outfile.json

The safe prime generator

Safe primes used in ZKRP can also be generated independently by the following command, where n is desired number of pairs of safe primes:

cargo run --release --example safe-primes n >outfile.json

Securing an application

Other tech remarks

References

[1] Gennaro, R., Goldfeder, S.: Fast multiparty threshold ecdsa with fast trustless setup.

[2] Shamir, A.: How to share a secret. Communications of the ACM 22(11), 612–613 (1979)

[3] Paillier, P.: Public-key cryptosystems based on composite degree residuosity classes. In: International Conference on the Theory and Applications of Cryptographic Techniques. pp. 223–238. Springer

[4] Eiichiro Fujisaki, Tatsuaki Okamoto: Statistical zero knowledge protocols to prove modular polynomial relations. Advances in Cryptology — CRYPTO '97 pp16-30

[5] Tillem, G., Burundukov, O.: Threshold signatures using Secure Multiparty Computation.

[6] Aumasson, J.P, Hamelink, A., Shlomovits, O.: A Survey of ECDSA Threshold Signing.

License

The product is released under the terms of the MIT license. See LICENSE for more information.

How to contribute

See CONTRIBUTING.md

Contacts

oleg.burundukov@ing.com

blockchain@ing.com