Rust implementation of {t,n}-threshold ECDSA (elliptic curve digital signature algorithm).

Overview

Multi-party ECDSA

Build Status License: GPL v3

This project is a Rust implementation of {t,n}-threshold ECDSA (elliptic curve digital signature algorithm).

Threshold ECDSA includes two protocols:

  • Key Generation for creating secret shares.
  • Signing for using the secret shares to generate a signature.

ECDSA is used extensively for crypto-currencies such as Bitcoin, Ethereum (secp256k1 curve), NEO (NIST P-256 curve) and much more. This library can be used to create MultiSig and ThresholdSig crypto wallet. For a full background on threshold signatures please read our Binance academy article Threshold Signatures Explained.

Library Introduction

The library was built with four core design principles in mind:

  1. Multi-protocol support
  2. Built for cryptography engineers
  3. Foolproof
  4. Black box use of cryptographic primitives

To learn about the core principles as well as on the audit process and security of the library, please read our Intro to multiparty ecdsa library blog post.

Use It

The library implements four different protocols for threshold ECDSA. The protocols presents different tradeoffs in terms of parameters, security assumptions and efficiency.

Protocol High Level code
Lindell 17 [1] Gotham-city (accepted to CIW19) is a two party bitcoin wallet, including benchmarks. KMS is a Rust wrapper library that implements a general purpose two party key management system. thresh-sig-js is a Javascript SDK
Gennaro, Goldfeder 19 [2] (video) tss-ecdsa-cli is a wrapper CLI for full threshold access structure, including network and threshold HD keys (BIP32). See Demo in this library to get better low level understanding
Castagnos et. al. 19 [3] Currently enabled as a feature in this library. To Enable, build with --features=cclst. to Test, use cargo test --features=cclst -- --test-threads=1
Gennaro, Goldfeder 20 [4] A full threshold protocol that supports identifying malicious parties. If signing fails - a list of malicious parties is returned. The protocol requires only a broadcast channel (all messages are broadcasted)

Run Demo

The following steps are for setup, key generation with n parties and signing with t+1 parties.

Setup

  1. We use shared state machine architecture (see white city). The parameters parties and threshold can be configured by changing the file: param. a keygen will run with parties parties and signing will run with any subset of threshold + 1 parties. param file should be located in the same path of the client software.

  2. Install Rust. Run cargo build --release --examples (it will build into /target/release/examples/)

  3. Run the shared state machine: ./sm_manager. Currently configured to be in 127.0.0.1:8001, this can be changed in Rocket.toml file. The Rocket.toml file should be in the same folder you run sm_manager from.

KeyGen

run gg18_keygen_client as follows: ./gg18_keygen_client http://127.0.0.1:8001 keys.store. Replace IP and port with the ones configured in setup. Once n parties join the application will run till finish. At the end each party will get a local keys file keys.store (change filename in command line). This contains secret and public data of the party after keygen. The file therefore should remain private.

Sign

Run ./gg18_sign_client. The application should be in the same folder as the keys.store file (or custom filename generated in keygen). the application takes three arguments: IP:port as in keygen, filename and message to be signed: ./gg18_sign_client http://127.0.0.1:8001 keys.store "KZen Networks". The same message should be used by all signers. Once t+1 parties join the protocol will run and will output to screen signature (R,s).

The ./gg18_sign_client executable initially tries to unhex its input message (the third parameter). Before running ensure two things:

  1. If you want to pass a binary message to be signed - hex it.
  2. If you want to pass a textual message in a non-hex form, make sure it can't be unhexed. Simply put, the safest way to use the signing binary is to just always hex your messages before passing them to the ./gg18_sign_client executable.

Example

To sign the message hello world, first calculate its hexadecimal representation. This yields the 68656c6c6f20776f726c64. Then, run:

./gg18_sign_client http://127.0.0.1:8001 keys.store "68656c6c6f20776f726c64"

GG18 demo

Run ./run.sh (located in /demo folder) in the main folder. Move params file to the same folder as the executables (usually /target/release/examples). The script will spawn a shared state machine, clients in the number of parties and signing requests for the threshold + 1 first parties.

sm_manager rocket server runs in production mode by default. You may modify the ./run.sh to config it to run in different environments. For example, to run rocket server in development:

ROCKET_ENV=development ./target/release/examples/sm_manager

GG20 demo

Run ./demo/run20.sh. You would need nightly rust toolchain and libgmp to be installed and available. The params.json file should be changed in case you want to change the default split of 2-of-3. The script starts sm_manager which exposes a shared state over http for message passing between parties. Multiple instances of the gg20_keygen_client and gg20_sign_client communicate via the sm_manager. This demo does not implement the identifiable abort portion of the protocol yet.

"Multiparty ECDSA Demo"
A 5 parties setup with 3 signers (threshold = 2)

Contributions & Development Process

The contribution workflow is described in CONTRIBUTING.md, in addition the Rust utilities wiki contains information on workflow and environment set-up.

License

Multi-party ECDSA is released under the terms of the GPL-3.0 license. See LICENSE for more information.

Contact

Feel free to reach out or join ZenGo X Telegram for discussions on code and research.

References

[1] https://eprint.iacr.org/2017/552.pdf

[2] https://eprint.iacr.org/2019/114.pdf

[3] https://eprint.iacr.org/2019/503.pdf

[4] https://eprint.iacr.org/2020/540.pdf

Comments
  • Support for `wasm32-unknown-unknown` target?

    Support for `wasm32-unknown-unknown` target?

    I have been investigating using multi-party ECDSA in WASM and wanted to know if there are plans to support the wasm32-unknown-unknown target so we could use this library from the browser?

    I have explored your emerald-city library and have used it to put together a very simple demo of using WASM (via wasm-pack) but would prefer to use something that is ready for production and has been audited, like this library or threshold-signatures.

    All my attempts to compile for wasm32-unknown-unknown have failed so far and when I tried with multi-party-ecdsa I get an error (that is now quite familiar!):

    error[E0046]: not all trait items implemented, missing: `encode`
        --> /home/muji/.cargo/registry/src/github.com-1ecc6299db9ec823/rustc-serialize-0.3.24/src/serialize.rs:1358:1
         |
    853  |     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error>;
         |     ---------------------------------------------------------------- `encode` from trait
    ...
    1358 | impl Encodable for path::Path {
         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `encode` in implementation
    
    error[E0046]: not all trait items implemented, missing: `decode`
        --> /home/muji/.cargo/registry/src/github.com-1ecc6299db9ec823/rustc-serialize-0.3.24/src/serialize.rs:1382:1
         |
    904  |     fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error>;
         |     ----------------------------------------------------------- `decode` from trait
    ...
    1382 | impl Decodable for path::PathBuf {
         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `decode` in implementation
    

    Which is due to the deprecated rustc-serialize library being used by rust-crypto. If we look at the code there is no implementation for the unknown target OS.

    We can't fix rustc-serialize so the solution I would imagine is to remove the dependency on rust-crypto which I believe is now deprecated in favour of RustCrypto.

    Would it be possible to merge the experimental work in emerald-city so we can build this library for WASM?

    Thanks :pray:

    opened by tmpfs 25
  • Problem with  gg20

    Problem with gg20

    Hi, I have problem with signing a "hello" sentence in the GG20 example. I am trying commands from the example and the result is:

    Error: online stage failed

    Caused by: couldn't complete signing: round 7: InvalidSig

    Please give me a small advice :) What I am doing wrong.

    opened by eatruffle 13
  • Value of R remains same every time when we generates `CompletedOfflineStage` with same `s_l`

    Value of R remains same every time when we generates `CompletedOfflineStage` with same `s_l`

    We are using 0.7.4 release tag. We have tried to implement GG20 and we are running Offline rounds (1-6) everytime when we generate signature and it gives same R's value in signature even if we are running Offline rounds before generate signature. Attaching logs may be that can help to see an issue.

    opened by aiyajsupra 11
  • Sign test gg20

    Sign test gg20

    I am intentionally opening a draft PR to show you where I am heading and get some early feedback in case I am going totally wrong. This is definitely not the final version of how I want to structure this. @omershlo

    I have totally skipped the blame steps for signing. That I am planning to keep for a future PR. I still need to grok that part better.

    I still have to:

    1. Add structures for all input/output pairs for keygen and sign.
    2. Right now the KeyPairResult has to be broken down so that until sign_stage8 there is no need for anything from keypair generation. That is essential for one round.
    3. Add comments all along for things that have to be private(encrypted for the intended party). Seems to be a long list.
    4. Some improvements to the interface like not passing full objects if only one of the items of the objects are needed in a stage.
    opened by nmahendru 10
  • Is there any instructions or examples for verifying the signature (for gg20)?

    Is there any instructions or examples for verifying the signature (for gg20)?

    Thanks for the great repository! I have walked through the example for GG20 keygen and signing. I can successfully generate the signature but I don't actually know how to extract the public key and actually verify the generated signature.

    Is there any instructions or examples that I can refer to? Thanks!

    opened by hcheng826 9
  • Sign_stage6 seems not to do what it's meant to

    Sign_stage6 seems not to do what it's meant to

    Hello,

    I was going through the library and got stuck at sign_stage6 method of orchestrate.rs. If I understand correctly, it corresponds to this line at page 15 of GG20 (specifically, the zero-knowledge proof part of it):

    Each player P_i broadcasts R_i = R^{k_i} as well as a zero-knowledge proof of consistency between R_i and E_i(k_i), which each player sent as the first message of the MtA protocol in Phase 2.

    But from the code it seems that we actually prove the statement t times, just with different Fujisaki-Okamoto commitments, and then verify our own proofs instead of broadcasting them. Also, I don't really understand why this stage is called in online stage of signing protocol (paper seems to suggest it can be done offline). Am I missing something?

    Thanks!

    opened by DmytroTym 6
  • Dependency does not exist on Crates.io

    Dependency does not exist on Crates.io

    At the moment it is not possible to build the project. The zeroize: 0.10.x has been yanked so cargo cannot find it.

    Shall we update the crate to the latest version?

    opened by ppoliani 6
  • Integrate Paillier for key generation encryption and ZK Proof

    Integrate Paillier for key generation encryption and ZK Proof

    This issue is dependent of https://github.com/KZen-networks/multi-party-ecdsa/issues/5. Code has been added to https://github.com/mortendahl/rust-paillier in order to do this. Need to be use in 2 party ECDSA.

    enhancement blocked 
    opened by gbenattar 6
  • Added a check for the length of PDLwSlackProof vector.

    Added a check for the length of PDLwSlackProof vector.

    Hey, @MatanHamilis! Sorry for taking so long to write two lines of code. Quite frankly, I just forgot about this. I think there are no more places in the code where the length check needs to be performed (in keygen round 3 and sign round 2, P2P container is used where parties need to send a list of messages). PS. I only added an assert_eq, without returning the vector of misbehaving parties. When implementing identifiable aborts, this should be changed. Or I can do it now.

    opened by DmytroTym 5
  • Failed to run examples

    Failed to run examples

    Here is my step:

    1. Git clone this repository, and build the examples
    2. Copy the Rocket.toml to ./target/release/examples
    3. Run the demo: ./demo/run.sh

    Here is error logs:

    $ ./demo/run.sh 
        Finished release [optimized] target(s) in 0.12s
    Params: {"parties":"3", "threshold":"1"}
    ./demo/run.sh: Multi-party ECDSA parties:3 threshold:1
    🔧 Configured for production.
        => address: 0.0.0.0
        => port: 8001
        => log: critical
        => workers: 12
        => secret key: private-cookies disabled
        => limits: forms = 32KiB
        => keep-alive: 5s
        => tls: disabled
    🚀 Rocket has launched from http://0.0.0.0:8001
    keygen part
    key gen for client 1 out of 3
    number: 1, uuid: "f2d83d40-c967-43f0-b468-4b1b5fdf0952"
    key gen for client 2 out of 3
    number: 2, uuid: "f2d83d40-c967-43f0-b468-4b1b5fdf0952"
    ["round1"] party 2 => party 1
    ["round1"] party 1 => party 2
    key gen for client 3 out of 3
    number: 3, uuid: "f2d83d40-c967-43f0-b468-4b1b5fdf0952"
    ["round1"] party 3 => party 2
    ["round1"] party 3 => party 1
    ["round1"] party 1 => party 3
    ["round2"] party 1 => party 2
    ["round2"] party 2 => party 1
    ["round1"] party 2 => party 3
    ["round2"] party 3 => party 2
    ["round2"] party 3 => party 1
    ["round2"] party 1 => party 3
    ["round2"] party 2 => party 3
    ["round3"] party 1 => party 2
    ["round3"] party 2 => party 1
    ["round3"] party 3 => party 2
    ["round3"] party 1 => party 3
    ["round3"] party 3 => party 1
    ["round4"] party 1 => party 2
    ["round3"] party 2 => party 3
    ["round4"] party 2 => party 1
    ["round4"] party 3 => party 2
    ["round4"] party 1 => party 3
    ["round4"] party 3 => party 1
    ["round5"] party 1 => party 2
    ["round4"] party 2 => party 3
    ["round5"] party 2 => party 1
    ["round5"] party 3 => party 2
    ["round5"] party 1 => party 3
    ["round5"] party 3 => party 1
    ["round5"] party 2 => party 3
    sign
    signing for client 1 out of 2
    number: 1, uuid: "051bea03-eb9c-43ec-9532-4251ffdbdfcd"
    signing for client 2 out of 2
    number: 2, uuid: "051bea03-eb9c-43ec-9532-4251ffdbdfcd"
    ["round0"] party 2 => party 1
    ["round0"] party 1 => party 2
    ["round1"] party 2 => party 1
    thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("invalid type: map, expected BigInt", line: 1, column: 77)', src/libcore/result.rs:1051:5
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
    ["round1"] party 1 => party 2
    thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("invalid type: map, expected BigInt", line: 1, column: 77)', src/libcore/result.rs:1051:5
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
    
    opened by flyq 5
  • Python bindings

    Python bindings

    Please let me know if there are any issues with this. Some code is commented out because I found that an unwrap would crash everything. I presume these issues are known. I didn't add deserialization support for all objects since I don't think they'll be sent over the wire. The code is very repetitive, I don't know what your policy regarding macros is.

    opened by ysangkok 5
  • Is it possible and practical to integrate the entire signing role, or `sm_client` to frontend implementation?

    Is it possible and practical to integrate the entire signing role, or `sm_client` to frontend implementation?

    I'm relatively new to Rust. Let me know if this question is totally off. My idea is to put the local-share into the local storage of browser extension or of mobile device. Just wondering if the Rust code of the core library (or gg20_sm_client.rs, gg20_signing.rs) can be integrated into those developments?

    opened by hcheng826 0
  • symbol not found in flat namespace '_rust_crypto_util_fixed_time_eq_asm'

    symbol not found in flat namespace '_rust_crypto_util_fixed_time_eq_asm'

    After cargo build, on running ./run.sh or run20.sh script, getting below error.

    keygen part key gen for client 1 out of 3 dyld[46200]: symbol not found in flat namespace '_rust_crypto_util_fixed_time_eq_asm' ./demo/run.sh: line 21: 46200 Abort trap: 6 ./target/release/examples/gg18_keygen_client http://127.0.0.1:8001 keys"$i".store key gen for client 2 out of 3 dyld[46202]: symbol not found in flat namespace '_rust_crypto_util_fixed_time_eq_asm' ./demo/run.sh: line 21: 46202 Abort trap: 6 ./target/release/examples/gg18_keygen_client http://127.0.0.1:8001 keys"$i".store key gen for client 3 out of 3 dyld[46204]: symbol not found in flat namespace '_rust_crypto_util_fixed_time_eq_asm' ./demo/run.sh: line 21: 46204 Abort trap: 6 ./target/release/examples/gg18_keygen_client http://127.0.0.1:8001 keys"$i".store sign signing for client 1 out of 2 thread 'main' panicked at 'Unable to load keys, did you run keygen first? : Os { code: 2, kind: NotFound, message: "No such file or directory" }', examples/gg18_sign_client.rs:47:10 note: run with RUST_BACKTRACE=1 environment variable to display a backtrace signing for client 2 out of 2 thread 'main' panicked at 'Unable to load keys, did you run keygen first? : Os { code: 2, kind: NotFound, message: "No such file or directory" }', examples/gg18_sign_client.rs:47:10 note: run with RUST_BACKTRACE=1 environment variable to display a backtrace

    System Software Overview:

      System Version: macOS 12.2.1 (21D62)
      Kernel Version: Darwin 21.3.0
      Boot Volume: Macintosh HD
      Boot Mode: Normal
    

    Hardware Overview:

      Model Name: MacBook Pro
      Model Identifier: MacBookPro18,1
      Chip: Apple M1 Pro
    
    opened by bhaagiKenpachi 3
  • Question about proof of pubkey consist

    Question about proof of pubkey consist

    Has the protocol some features to proof that the public key participates in the multisig or that the multisig is created by a set of public keys? There is some task to proof that some user is part of multisig or some group of users created a multisig. If it is possible how can it be done?

    opened by b33ngo 1
  • Is this a malicious action if false?

    Is this a malicious action if false?

    https://github.com/ZenGo-X/multi-party-ecdsa/blob/9193fb7d42178fe854688b1874a9a7cd61b540c9/src/protocols/multi_party_ecdsa/gg_2020/state_machine/sign/rounds.rs#L259

    opened by drewstone 0
Releases(v0.4.6)
Owner
[ZenGo X]
Threshold cryptography for blockchains. Projects with "city" in name are work in progress.
[ZenGo X]
Elliptic-curves - Collection of pure Rust elliptic curve implementations (e.g. P-256, P-384, secp256k1)

RustCrypto: Elliptic Curves General purpose Elliptic Curve Cryptography (ECC) support, including types and traits for representing various elliptic cu

Rust Crypto 386 Dec 27, 2022
Multi Party Key Management System (KMS) for Secp256k1 Elliptic curve based digital signatures.

Key Management System (KMS) for curve Secp256k1 Multi Party Key Management System (KMS) for Secp256k1 Elliptic curve based digital signatures. Introdu

[ZenGo X] 61 Dec 28, 2022
Multy-party threshold ECDSA Substrate node

Webb DKG ??️ The Webb DKG ??‍✈️ ⚠️ Beta Software ⚠️ Running the DKG Currently the easiest way to run the DKG is to use a 3-node local testnet using dk

webb 42 Dec 19, 2022
Cryptographic signature algorithms: ECDSA, Ed25519

RustCrypto: signatures Support for digital signatures, which provide authentication of data using public-key cryptography. All algorithms reside in th

Rust Crypto 300 Jan 8, 2023
ECDSA Signature Server

Simple REST API used for serving ECDSA signatures to prevent automation software from minting NFTs in bulk.

Jonathan 3 Nov 30, 2022
Implementation of the BLS12-381 pairing-friendly elliptic curve group

bls12_381 This crate provides an implementation of the BLS12-381 pairing-friendly elliptic curve construction. This implementation has not been review

Zero-knowledge Cryptography in Rust 183 Dec 27, 2022
X25519 elliptic curve Diffie-Hellman key exchange in pure-Rust, using curve25519-dalek.

x25519-dalek A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key exchange, with curve operations provided by curve25519-dalek. This

dalek cryptography 252 Dec 26, 2022
Elliptic curve cryptography on Soroban.

Elliptic Curve Cryptography on Soroban Contract examples and reusable primitives. Groth 16 verifier. This crate provides a SorobanGroth16Verifier obje

Xycloo Labs 5 Feb 10, 2023
A pure-Rust implementation of various threshold secret sharing schemes

Threshold Secret Sharing Efficient pure-Rust library for secret sharing, offering efficient share generation and reconstruction for both traditional S

Snips 137 Dec 29, 2022
Bulletproofs and Bulletproofs+ Rust implementation for Aggregated Range Proofs over multiple elliptic curves

Bulletproofs This library implements Bulletproofs+ and Bulletproofs aggregated range proofs with multi-exponent verification. The library supports mul

[ZenGo X] 62 Dec 13, 2022
Rust implementation of multi-party Schnorr signatures over elliptic curves.

Multi Party Schnorr Signatures This library contains several Rust implementations of multi-signature Schnorr schemes. Generally speaking, these scheme

[ZenGo X] 148 Dec 15, 2022
A pairing-based threshold cryptosystem for collaborative decryption and signatures used in HoneybadgerBFT implementation

threshold_crypto A pairing-based threshold cryptosystem for collaborative decryption and signatures. The threshold_crypto crate provides cryptographic

null 166 Dec 29, 2022
Two-party and multi-party ECDSA protocols based on class group with Rust

CG-MPC-ECDSA This project aims to implement two-party and multi-party ECDSA protocols based on class group with Rust. It currently includes schemes de

LatticeX Foundation 16 Mar 17, 2022
Pure Rust implementation of the Leighton Micali Signature scheme.

Leighton-Micali Hash-Based Signatures LMS implementation in Rust according to the IETF RFC 8554. This implementation is binary compatible with the ref

Fraunhofer AISEC 6 Jun 2, 2022
Implementation of the Grumpkin curve in Rust.

Grumpkin curve implementation in Rust This repository implements the Grumpkin curve for use in Rust, by building off of the code provided by ZCash and

Jules 3 Dec 26, 2022
🔑 Threshold Shamir's secret sharing in Rust

Rusty Secrets Rusty Secrets is an implementation of a threshold Shamir's secret sharing scheme. Documentation (latest) Documentation (master) Design g

Spin Research 233 Dec 17, 2022
Rust library for practical time-lock encryption using `drand` threshold network

tlock-rs: Practical Timelock Encryption/Decryption in Rust This repo contains pure Rust implementation of drand/tlock scheme. It provides time-based e

Timofey 32 Jan 8, 2023
Baek-Zheng threshold cryptosystem on top of BLS12-381

bzte A rust implementation of the Baek-Zhang threshold cryptosystem on top of BLS12-381 using arkworks Why threshold encrypt? The advantage of thresho

null 4 Jun 28, 2022
L2 validity rollup combined with blind signatures over elliptic curves inside zkSNARK, to provide offchain anonymous voting with onchain binding execution on Ethereum

blind-ovote Blind-OVOTE is a L2 voting solution which combines the validity rollup ideas with blind signatures over elliptic curves inside zkSNARK, to

Aragon ZK Research 3 Nov 18, 2022