mirror of
https://github.com/luxfi/multi-party-ecdsa.git
synced 2026-10-30 15:24:24 +00:00
272 lines
8.1 KiB
Rust
272 lines
8.1 KiB
Rust
#![allow(non_snake_case)]
|
|
/// to run:
|
|
/// 1: go to rocket_server -> cargo run
|
|
/// 2: cargo run from PARTIES number of terminals
|
|
use curv::{
|
|
arithmetic::traits::Converter,
|
|
cryptographic_primitives::{
|
|
proofs::sigma_dlog::DLogProof, secret_sharing::feldman_vss::VerifiableSS,
|
|
},
|
|
elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar},
|
|
BigInt,
|
|
};
|
|
use multi_party_ecdsa::protocols::multi_party_ecdsa::gg_2018::party_i::{
|
|
KeyGenBroadcastMessage1, KeyGenDecommitMessage1, Keys, Parameters,
|
|
};
|
|
use paillier::EncryptionKey;
|
|
use reqwest::Client;
|
|
use sha2::Sha256;
|
|
use std::{env, fs, time};
|
|
|
|
mod common;
|
|
use common::{
|
|
aes_decrypt, aes_encrypt, broadcast, poll_for_broadcasts, poll_for_p2p, postb, sendp2p, Params,
|
|
PartySignup, AEAD, AES_KEY_BYTES_LEN,
|
|
};
|
|
|
|
fn main() {
|
|
if env::args().nth(3).is_some() {
|
|
panic!("too many arguments")
|
|
}
|
|
if env::args().nth(2).is_none() {
|
|
panic!("too few arguments")
|
|
}
|
|
//read parameters:
|
|
let data = fs::read_to_string("params.json")
|
|
.expect("Unable to read params, make sure config file is present in the same folder ");
|
|
let params: Params = serde_json::from_str(&data).unwrap();
|
|
let PARTIES: u16 = params.parties.parse::<u16>().unwrap();
|
|
let THRESHOLD: u16 = params.threshold.parse::<u16>().unwrap();
|
|
|
|
let client = Client::new();
|
|
|
|
// delay:
|
|
let delay = time::Duration::from_millis(25);
|
|
let params = Parameters {
|
|
threshold: THRESHOLD,
|
|
share_count: PARTIES,
|
|
};
|
|
|
|
//signup:
|
|
let (party_num_int, uuid) = match signup(&client).unwrap() {
|
|
PartySignup { number, uuid } => (number, uuid),
|
|
};
|
|
println!("number: {:?}, uuid: {:?}", party_num_int, uuid);
|
|
|
|
let party_keys = Keys::create(party_num_int);
|
|
let (bc_i, decom_i) = party_keys.phase1_broadcast_phase3_proof_of_correct_key();
|
|
|
|
// send commitment to ephemeral public keys, get round 1 commitments of other parties
|
|
assert!(broadcast(
|
|
&client,
|
|
party_num_int,
|
|
"round1",
|
|
serde_json::to_string(&bc_i).unwrap(),
|
|
uuid.clone()
|
|
)
|
|
.is_ok());
|
|
let round1_ans_vec = poll_for_broadcasts(
|
|
&client,
|
|
party_num_int,
|
|
PARTIES,
|
|
delay,
|
|
"round1",
|
|
uuid.clone(),
|
|
);
|
|
|
|
let mut bc1_vec = round1_ans_vec
|
|
.iter()
|
|
.map(|m| serde_json::from_str::<KeyGenBroadcastMessage1>(m).unwrap())
|
|
.collect::<Vec<_>>();
|
|
|
|
bc1_vec.insert(party_num_int as usize - 1, bc_i);
|
|
|
|
// send ephemeral public keys and check commitments correctness
|
|
assert!(broadcast(
|
|
&client,
|
|
party_num_int,
|
|
"round2",
|
|
serde_json::to_string(&decom_i).unwrap(),
|
|
uuid.clone()
|
|
)
|
|
.is_ok());
|
|
let round2_ans_vec = poll_for_broadcasts(
|
|
&client,
|
|
party_num_int,
|
|
PARTIES,
|
|
delay,
|
|
"round2",
|
|
uuid.clone(),
|
|
);
|
|
|
|
let mut j = 0;
|
|
let mut point_vec: Vec<Point<Secp256k1>> = Vec::new();
|
|
let mut decom_vec: Vec<KeyGenDecommitMessage1> = Vec::new();
|
|
let mut enc_keys: Vec<Vec<u8>> = Vec::new();
|
|
for i in 1..=PARTIES {
|
|
if i == party_num_int {
|
|
point_vec.push(decom_i.y_i.clone());
|
|
decom_vec.push(decom_i.clone());
|
|
} else {
|
|
let decom_j: KeyGenDecommitMessage1 = serde_json::from_str(&round2_ans_vec[j]).unwrap();
|
|
point_vec.push(decom_j.y_i.clone());
|
|
decom_vec.push(decom_j.clone());
|
|
let key_bn: BigInt = (decom_j.y_i.clone() * party_keys.u_i.clone())
|
|
.x_coord()
|
|
.unwrap();
|
|
let key_bytes = BigInt::to_bytes(&key_bn);
|
|
let mut template: Vec<u8> = vec![0u8; AES_KEY_BYTES_LEN - key_bytes.len()];
|
|
template.extend_from_slice(&key_bytes[..]);
|
|
enc_keys.push(template);
|
|
j += 1;
|
|
}
|
|
}
|
|
|
|
let (head, tail) = point_vec.split_at(1);
|
|
let y_sum = tail.iter().fold(head[0].clone(), |acc, x| acc + x);
|
|
|
|
let (vss_scheme, secret_shares, _index) = party_keys
|
|
.phase1_verify_com_phase3_verify_correct_key_phase2_distribute(
|
|
¶ms, &decom_vec, &bc1_vec,
|
|
)
|
|
.expect("invalid key");
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
let mut j = 0;
|
|
for (k, i) in (1..=PARTIES).enumerate() {
|
|
if i != party_num_int {
|
|
// prepare encrypted ss for party i:
|
|
let key_i = &enc_keys[j];
|
|
let plaintext = BigInt::to_bytes(&secret_shares[k].to_bigint());
|
|
let aead_pack_i = aes_encrypt(key_i, &plaintext);
|
|
assert!(sendp2p(
|
|
&client,
|
|
party_num_int,
|
|
i,
|
|
"round3",
|
|
serde_json::to_string(&aead_pack_i).unwrap(),
|
|
uuid.clone()
|
|
)
|
|
.is_ok());
|
|
j += 1;
|
|
}
|
|
}
|
|
|
|
let round3_ans_vec = poll_for_p2p(
|
|
&client,
|
|
party_num_int,
|
|
PARTIES,
|
|
delay,
|
|
"round3",
|
|
uuid.clone(),
|
|
);
|
|
|
|
let mut j = 0;
|
|
let mut party_shares: Vec<Scalar<Secp256k1>> = Vec::new();
|
|
for i in 1..=PARTIES {
|
|
if i == party_num_int {
|
|
party_shares.push(secret_shares[(i - 1) as usize].clone());
|
|
} else {
|
|
let aead_pack: AEAD = serde_json::from_str(&round3_ans_vec[j]).unwrap();
|
|
let key_i = &enc_keys[j];
|
|
let out = aes_decrypt(key_i, aead_pack);
|
|
let out_bn = BigInt::from_bytes(&out[..]);
|
|
let out_fe = Scalar::<Secp256k1>::from(&out_bn);
|
|
party_shares.push(out_fe);
|
|
|
|
j += 1;
|
|
}
|
|
}
|
|
|
|
// round 4: send vss commitments
|
|
assert!(broadcast(
|
|
&client,
|
|
party_num_int,
|
|
"round4",
|
|
serde_json::to_string(&vss_scheme).unwrap(),
|
|
uuid.clone()
|
|
)
|
|
.is_ok());
|
|
let round4_ans_vec = poll_for_broadcasts(
|
|
&client,
|
|
party_num_int,
|
|
PARTIES,
|
|
delay,
|
|
"round4",
|
|
uuid.clone(),
|
|
);
|
|
|
|
let mut j = 0;
|
|
let mut vss_scheme_vec: Vec<VerifiableSS<Secp256k1>> = Vec::new();
|
|
for i in 1..=PARTIES {
|
|
if i == party_num_int {
|
|
vss_scheme_vec.push(vss_scheme.clone());
|
|
} else {
|
|
let vss_scheme_j: VerifiableSS<Secp256k1> =
|
|
serde_json::from_str(&round4_ans_vec[j]).unwrap();
|
|
vss_scheme_vec.push(vss_scheme_j);
|
|
j += 1;
|
|
}
|
|
}
|
|
|
|
let (shared_keys, dlog_proof) = party_keys
|
|
.phase2_verify_vss_construct_keypair_phase3_pok_dlog(
|
|
¶ms,
|
|
&point_vec,
|
|
&party_shares,
|
|
&vss_scheme_vec,
|
|
party_num_int,
|
|
)
|
|
.expect("invalid vss");
|
|
|
|
// round 5: send dlog proof
|
|
assert!(broadcast(
|
|
&client,
|
|
party_num_int,
|
|
"round5",
|
|
serde_json::to_string(&dlog_proof).unwrap(),
|
|
uuid.clone()
|
|
)
|
|
.is_ok());
|
|
let round5_ans_vec =
|
|
poll_for_broadcasts(&client, party_num_int, PARTIES, delay, "round5", uuid);
|
|
|
|
let mut j = 0;
|
|
let mut dlog_proof_vec: Vec<DLogProof<Secp256k1, Sha256>> = Vec::new();
|
|
for i in 1..=PARTIES {
|
|
if i == party_num_int {
|
|
dlog_proof_vec.push(dlog_proof.clone());
|
|
} else {
|
|
let dlog_proof_j: DLogProof<Secp256k1, Sha256> =
|
|
serde_json::from_str(&round5_ans_vec[j]).unwrap();
|
|
dlog_proof_vec.push(dlog_proof_j);
|
|
j += 1;
|
|
}
|
|
}
|
|
Keys::verify_dlog_proofs(¶ms, &dlog_proof_vec, &point_vec).expect("bad dlog proof");
|
|
|
|
//save key to file:
|
|
let paillier_key_vec = (0..PARTIES)
|
|
.map(|i| bc1_vec[i as usize].e.clone())
|
|
.collect::<Vec<EncryptionKey>>();
|
|
|
|
let keygen_json = serde_json::to_string(&(
|
|
party_keys,
|
|
shared_keys,
|
|
party_num_int,
|
|
vss_scheme_vec,
|
|
paillier_key_vec,
|
|
y_sum,
|
|
))
|
|
.unwrap();
|
|
fs::write(env::args().nth(2).unwrap(), keygen_json).expect("Unable to save !");
|
|
}
|
|
|
|
pub fn signup(client: &Client) -> Result<PartySignup, ()> {
|
|
let key = "signup-keygen".to_string();
|
|
|
|
let res_body = postb(client, "signupkeygen", key).unwrap();
|
|
serde_json::from_str(&res_body).unwrap()
|
|
}
|