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

Feature/curv 0.9 #10

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,3 @@ Cargo.lock
**/*.rs.bk
.idea
*.priv
*.store
29 changes: 22 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tss-cli"
version = "0.1.0"
version = "0.2.0"
authors = [
"Kaspars Sprogis <[email protected]>"
]
Expand All @@ -20,18 +20,33 @@ reqwest = { version = "0.10.1", default-features = false, features = ["native-tl
uuid = { version = "0.8", features = ["v4"] }
aes-gcm = "0.9.4"
libsecp256k1 = "0.3.2"
curv = { package = "curv-kzen", version = "0.7", default-features = false }
paillier = { git = "https://github.com/KZen-networks/rust-paillier", tag = "v0.3.10"}
zk-paillier = { git = "https://github.com/KZen-networks/zk-paillier", tag = "v0.3.12"}
curv = { package = "curv-kzen", version = "0.9", default-features = false }
zk-paillier = { git = "https://github.com/KZen-networks/zk-paillier", tag = "v0.4.2"}
clap = { version = "2.33", features = ["yaml"] }
hmac = "0.11"
sha2 = "0.9"
rand = "0.8"

[dependencies.paillier]
version = "0.4.2"
package = "kzen-paillier"
default-features = false

[dependencies.multi-party-ecdsa]
git = "https://github.com/Hrezaei/multi-party-ecdsa"
git = "https://github.com/ZenGo-X/multi-party-ecdsa"
#tag = "v0.3.0"
branch = "feature/deprecate-rust-crypto"
branch = "master"

[dependencies.multi-party-eddsa]
git = "https://github.com/HRezaei/multi-party-eddsa"
branch = "feature/curv-0.9-examples"

[patch.crates-io]
rust-gmp = { version = "0.5.1", features = ["serde_support"], git = "https://github.com/KZen-networks/rust-gmp" }

[profile.release]
opt-level = 2
opt-level = 2


[features]
default = ["curv/rust-gmp-kzen"]
28 changes: 16 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
# TSS ECDSA CLI utility
# TSS ECDSA/EdDSA CLI Utility

[![Build Status](https://travis-ci.com/cryptochill/tss-ecdsa-cli.svg?branch=master)](https://travis-ci.com/cryptochill/tss-ecdsa-cli)
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)

This project is an example usage of https://github.com/KZen-networks/multi-party-ecdsa library which is a Rust implementation of {t,n}-threshold ECDSA.
This project is an example usage of https://github.com/KZen-networks/multi-party-ecdsa library which is a Rust implementation of {t,n}-threshold ECDSA.

It also supports EdDSA, based on the examples of https://github.com/HRezaei/multi-party-eddsa.

Includes support for HD keys ([BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)). HD support based on https://github.com/trepca/multi-party-ecdsa/tree/hd-support.

## Setup

1. Install [Rust](https://rustup.rs/) nightly ([Rocket](https://rocket.rs/v0.4/guide/getting-started/) requires the latest version of Rust nightly).
1. Install [Rust](https://rustup.rs/).

```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup default nightly
```

2. Clone & build.
Expand All @@ -34,7 +35,7 @@ Includes support for HD keys ([BIP32](https://github.com/bitcoin/bips/blob/maste

To run on different host/port adjust Rocket.toml or override using [env vars](https://api.rocket.rs/v0.4/rocket/config/index.html#environment-variables).
```sh
ROCKET_ADDRESS=127.0.0.1 ROCKET_PORT=8008 ./target/release/tss_cli
ROCKET_ADDRESS=127.0.0.1 ROCKET_PORT=8008 ./target/release/tss_cli manager
```

2. Run keygen:
Expand All @@ -44,8 +45,9 @@ Includes support for HD keys ([BIP32](https://github.com/bitcoin/bips/blob/maste
tss_cli keygen [OPTIONS] <keysfile> <params>

OPTIONS:
-a, --addr <manager_addr> URL to manager. E.g. http://127.0.0.2:8002

-a, --addr <manager_addr> URL to manager. E.g. --addr http://127.0.0.2:8002
-c, --curve <curve name> Either of ecdsa (default) or eddsa. E.g. -curve eddsa

ARGS:
<keysfile> Target keys file
<params> Threshold params: threshold/parties (t+1/n). E.g. 1/3 for 2 of 3 schema.
Expand All @@ -55,7 +57,7 @@ Includes support for HD keys ([BIP32](https://github.com/bitcoin/bips/blob/maste
t=1 && n=3; for i in $(seq 1 $n)
do
echo "key gen for client $i out of $n"
./target/release/tss_cli keygen keys$i.store $t/$n &
./target/release/tss_cli keygen keys_ecdsa_$i.store $t/$n -cecdsa &
sleep 2
done
```
Expand All @@ -70,14 +72,15 @@ USAGE:

OPTIONS:
-p, --path <path> Derivation path
-c, --curve <curve name> Either of ecdsa (default) or eddsa. E.g. -curve eddsa

ARGS:
<keysfile> Keys file

./target/release/tss_cli pubkey keys1.store
./target/release/tss_cli pubkey keys_ecdsa_1.store
# Output: {"path":"","x":"20d6d63f5baa237c747c33dd85170e186d31fa2948b3bb4615e7d08045f05614","y":"6b4ae2e5a65f750f911e92f365f8f4733949f4681efb9ebfa8d9d8fec258e96"}

./target/release/tss_cli pubkey keys1.store -p 0/1/2
./target/release/tss_cli pubkey keys_eddsa_1.store -p 0/1/2 -c eddsa
# Output: {"path":"0/1/2","x":"973dba2e6c622d0d62626b5cc20e9561dd6123afca96d7b811f637900e68d99e","y":"7c1b2d91cdbfd6e9ceab48dc94aedfd021e314f4d90d18cbb8a4b40d543f85cd"}
```

Expand All @@ -92,15 +95,16 @@ USAGE:
OPTIONS:
-a, --addr <manager_addr> URL to manager
-p, --path <path> Derivation path
-c, --curve <curve name> Either of ecdsa (default) or eddsa. E.g. -curve eddsa

ARGS:
<keysfile> Keys file
<params> Threshold params: threshold/parties (t+1/n). E.g. 1/3 for 2 of 3 schema.
<message> Message to sign in hex format


./target/release/tss_cli sign keys1.store -p 0/1/2 -a http://127.0.0.1:8001 1/2 SignMe
./target/release/tss_cli sign keys2.store -p 0/1/2 -a http://127.0.0.1:8001 1/2 SignMe
./target/release/tss_cli sign keys_ecdsa_1.store -p 0/1/2 -a http://127.0.0.1:8001 1/2 SignMe -cecdsa
./target/release/tss_cli sign keys_ecdsa_2.store -p 0/1/2 -a http://127.0.0.1:8001 1/2 SignMe -cecdsa

# If all is correct, last line of the output should be json string, something like this:
{
Expand Down
67 changes: 35 additions & 32 deletions src/common/hd_keys.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
extern crate curv;

use curv::arithmetic::traits::Converter;
use curv::cryptographic_primitives::hashing::hmac_sha512;
use curv::cryptographic_primitives::hashing::traits::KeyedHash;
use curv::elliptic::curves::traits::*;
use curv::{
BigInt,
elliptic::curves::secp256_k1::{FE, GE},
arithmetic::{BasicOps, One}
};

use curv::arithmetic::{Converter, BasicOps, One};
use curv::BigInt;
use curv::elliptic::curves::{Curve, Point, Scalar};

pub fn get_hd_key(y_sum: &GE, path_vector: Vec<BigInt>) -> (GE, FE) {
use curv::cryptographic_primitives::hashing::HmacExt;
use hmac::Hmac;
use sha2::{Sha512};


pub fn get_hd_key<E: Curve>(y_sum: &Point<E>, path_vector: Vec<BigInt>) -> (Point<E>, Scalar<E>) {
// generate a random but shared chain code, this will do
let chain_code = GE::generator();
let chain_code = Point::<E>::generator();
// println!("chain code {:?}", chain_code);
// derive a new pubkey and LR sequence, y_sum becomes a new child pub key
let (y_sum_child, f_l_new, _cc_new) = hd_key(
path_vector,
&y_sum,
&chain_code.bytes_compressed_to_big_int(),
&BigInt::from_bytes(&chain_code.to_bytes(true)),
);
let y_sum = y_sum_child.clone();
// println!("New public key: {:?}", &y_sum);
Expand All @@ -28,43 +26,48 @@ pub fn get_hd_key(y_sum: &GE, path_vector: Vec<BigInt>) -> (GE, FE) {
(y_sum, f_l_new)
}

pub fn hd_key(
pub fn hd_key<E: Curve>(
mut location_in_hir: Vec<BigInt>,
pubkey: &GE,
pubkey: &Point<E>,
chain_code_bi: &BigInt,
) -> (GE, FE, GE) {
let mask = BigInt::from(2).pow(256) - BigInt::one();
) -> (Point<E>, Scalar<E>, Point<E>) {
let mask = BigInt::from(2 as i32).pow(256) - BigInt::one();
// let public_key = self.public.q.clone();

// calc first element:
let first = location_in_hir.remove(0);
let pub_key_bi = pubkey.bytes_compressed_to_big_int();
let f = hmac_sha512::HMacSha512::create_hmac(&chain_code_bi, &[&pub_key_bi, &first]);
let pub_key_bi = BigInt::from_bytes(&pubkey.to_bytes(true));
let f = Hmac::<Sha512>::new_bigint(chain_code_bi)
.chain_bigint(&pub_key_bi)
.chain_bigint(&first)
.result_bigint();

let f_l = &f >> 256;
let f_r = &f & &mask;
let f_l_fe: FE = ECScalar::from(&f_l);
let f_r_fe: FE = ECScalar::from(&f_r);
let f_l_fe: Scalar<E> = Scalar::<E>::from(&f_l);
let f_r_fe: Scalar<E> = Scalar::<E>::from(&f_r);

let bn_to_slice = BigInt::to_bytes(chain_code_bi);
let chain_code = GE::from_bytes(&bn_to_slice[1..33]).unwrap() * &f_r_fe;
let g: GE = ECPoint::generator();
let pub_key = *pubkey + g * &f_l_fe;
let chain_code = Point::<E>::from_bytes(&bn_to_slice.as_slice()).unwrap() * &f_r_fe;
let g: Point<E> = Point::<E>::generator().to_point();
let pub_key = pubkey.clone() + g.clone() * &f_l_fe;

let (public_key_new_child, f_l_new, cc_new) =
location_in_hir
.iter()
.fold((pub_key, f_l_fe, chain_code), |acc, index| {
let pub_key_bi = acc.0.bytes_compressed_to_big_int();
let f = hmac_sha512::HMacSha512::create_hmac(
&acc.2.bytes_compressed_to_big_int(),
&[&pub_key_bi, index],
);
let pub_key_bi = BigInt::from_bytes(&acc.0.to_bytes(true));
let f = Hmac::<Sha512>::new_bigint(&BigInt::from_bytes(&acc.2.to_bytes(true)))
.chain_bigint(&pub_key_bi)
.chain_bigint(index)
.result_bigint();

let f_l = &f >> 256;
let f_r = &f & &mask;
let f_l_fe: FE = ECScalar::from(&f_l);
let f_r_fe: FE = ECScalar::from(&f_r);
let f_l_fe: Scalar<E> = Scalar::<E>::from(&f_l);
let f_r_fe: Scalar<E> = Scalar::<E>::from(&f_r);

(acc.0 + g * &f_l_fe, f_l_fe + &acc.1, &acc.2 * &f_r_fe)
(acc.0 + &g * &f_l_fe, f_l_fe + &acc.1, &acc.2 * &f_r_fe)
});
(public_key_new_child, f_l_new, cc_new)
}
60 changes: 32 additions & 28 deletions src/common/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,30 @@ pub async fn run_manager() -> Result<(), rocket::Error> {
//////////////////////////init signups://////////////////////////
/////////////////////////////////////////////////////////////////

let keygen_key = "signup-keygen".to_string();
let sign_key = "signup-sign".to_string();

let uuid_keygen = Uuid::new_v4().to_string();
let uuid_sign = Uuid::new_v4().to_string();

let party1 = 0;
let party_signup_keygen = PartySignup {
number: party1,
uuid: uuid_keygen,
};
let party_signup_sign = PartySignup {
number: party1,
uuid: uuid_sign,
};
{
let mut hm = db_mtx.write().unwrap();
hm.insert(
keygen_key,
serde_json::to_string(&party_signup_keygen).unwrap(),
);
hm.insert(sign_key, serde_json::to_string(&party_signup_sign).unwrap());
for curve_name in ["ECDSA", "EdDSA"] {
let keygen_key = "signup-keygen-".to_string() + curve_name;
let sign_key = "signup-sign-".to_string() + curve_name;

let uuid_keygen = Uuid::new_v4().to_string();
let uuid_sign = Uuid::new_v4().to_string();

let party1 = 0;
let party_signup_keygen = PartySignup {
number: party1,
uuid: uuid_keygen,
};
let party_signup_sign = PartySignup {
number: party1,
uuid: uuid_sign,
};
{
let mut hm = db_mtx.write().unwrap();
hm.insert(
keygen_key,
serde_json::to_string(&party_signup_keygen).unwrap(),
);
hm.insert(sign_key, serde_json::to_string(&party_signup_sign).unwrap());
}
}
/////////////////////////////////////////////////////////////////
rocket::build()
Expand Down Expand Up @@ -81,10 +83,11 @@ fn set(db_mtx: &State<RwLock<HashMap<Key, String>>>, request: Json<Entry>) -> Js
#[post("/signupkeygen", format = "json", data = "<request>")]
fn signup_keygen(
db_mtx: &State<RwLock<HashMap<Key, String>>>,
request: Json<Params>,
request: Json<(Params, String)>,
) -> Json<Result<PartySignup, ()>> {
let parties = request.parties.parse::<u16>().unwrap();
let key = "signup-keygen".to_string();
let parties = request.0.0.parties.parse::<u16>().unwrap();
let curve = &request.0.1.parse::<String>().unwrap();
let key = "signup-keygen-".to_string() + curve;

let mut hm = db_mtx.write().unwrap();

Expand Down Expand Up @@ -122,10 +125,11 @@ fn signup_keygen(
#[post("/signupsign", format = "json", data = "<request>")]
fn signup_sign(
db_mtx: &State<RwLock<HashMap<Key, String>>>,
request: Json<Params>,
request: Json<(Params, String)>,
) -> Json<Result<PartySignup, ()>> {
let threshold = request.threshold.parse::<u16>().unwrap();
let key = "signup-sign".to_string();
let threshold = request.0.0.threshold.parse::<u16>().unwrap();
let curve = &request.0.1.parse::<String>().unwrap();
let key = "signup-sign-".to_string() + curve;

let mut hm = db_mtx.write().unwrap();

Expand Down
Loading