#![allow(non_snake_case)] use curv::{ arithmetic::traits::*, cryptographic_primitives::{ proofs::sigma_correct_homomorphic_elgamal_enc::HomoELGamalProof, 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::{ Keys, LocalSignature, PartyPrivate, Phase5ADecom1, Phase5Com1, Phase5Com2, Phase5DDecom2, SharedKeys, SignBroadcastPhase1, SignDecommitPhase1, SignKeys, }; use multi_party_ecdsa::utilities::mta::*; use sha2::Sha256; use paillier::EncryptionKey; use reqwest::Client; use std::{env, fs, time}; mod common; use common::{ broadcast, check_sig, poll_for_broadcasts, poll_for_p2p, postb, sendp2p, Params, PartySignup, }; #[allow(clippy::cognitive_complexity)] fn main() { if env::args().nth(4).is_some() { panic!("too many arguments") } if env::args().nth(3).is_none() { panic!("too few arguments") } let message_str = env::args().nth(3).unwrap_or_else(|| "".to_string()); let message = match hex::decode(message_str.clone()) { Ok(x) => x, Err(_e) => message_str.as_bytes().to_vec(), }; let message = &message[..]; let client = Client::new(); // delay: let delay = time::Duration::from_millis(25); // read key file let data = fs::read_to_string(env::args().nth(2).unwrap()) .expect("Unable to load keys, did you run keygen first? "); let (party_keys, shared_keys, party_id, vss_scheme_vec, paillier_key_vector, y_sum): ( Keys, SharedKeys, u16, Vec>, Vec, Point, ) = serde_json::from_str(&data).unwrap(); //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 THRESHOLD = params.threshold.parse::().unwrap(); //signup: let (party_num_int, uuid) = match signup(&client).unwrap() { PartySignup { number, uuid } => (number, uuid), }; println!("number: {:?}, uuid: {:?}", party_num_int, uuid); // round 0: collect signers IDs assert!(broadcast( &client, party_num_int, "round0", serde_json::to_string(&party_id).unwrap(), uuid.clone() ) .is_ok()); let round0_ans_vec = poll_for_broadcasts( &client, party_num_int, THRESHOLD + 1, delay, "round0", uuid.clone(), ); let mut j = 0; let mut signers_vec: Vec = Vec::new(); for i in 1..=THRESHOLD + 1 { if i == party_num_int { signers_vec.push(party_id - 1); } else { let signer_j: u16 = serde_json::from_str(&round0_ans_vec[j]).unwrap(); signers_vec.push(signer_j - 1); j += 1; } } let private = PartyPrivate::set_private(party_keys.clone(), shared_keys); let sign_keys = SignKeys::create( &private, &vss_scheme_vec[usize::from(signers_vec[usize::from(party_num_int - 1)])], signers_vec[usize::from(party_num_int - 1)], &signers_vec, ); let xi_com_vec = Keys::get_commitments_to_xi(&vss_scheme_vec); ////////////////////////////////////////////////////////////////////////////// let (com, decommit) = sign_keys.phase1_broadcast(); let (m_a_k, _) = MessageA::a(&sign_keys.k_i, &party_keys.ek, &[]); assert!(broadcast( &client, party_num_int, "round1", serde_json::to_string(&(com.clone(), m_a_k)).unwrap(), uuid.clone() ) .is_ok()); let round1_ans_vec = poll_for_broadcasts( &client, party_num_int, THRESHOLD + 1, delay, "round1", uuid.clone(), ); let mut j = 0; let mut bc1_vec: Vec = Vec::new(); let mut m_a_vec: Vec = Vec::new(); for i in 1..THRESHOLD + 2 { if i == party_num_int { bc1_vec.push(com.clone()); // m_a_vec.push(m_a_k.clone()); } else { // if signers_vec.contains(&(i as usize)) { let (bc1_j, m_a_party_j): (SignBroadcastPhase1, MessageA) = serde_json::from_str(&round1_ans_vec[j]).unwrap(); bc1_vec.push(bc1_j); m_a_vec.push(m_a_party_j); j += 1; // } } } assert_eq!(signers_vec.len(), bc1_vec.len()); ////////////////////////////////////////////////////////////////////////////// let mut m_b_gamma_send_vec: Vec = Vec::new(); let mut beta_vec: Vec> = Vec::new(); let mut m_b_w_send_vec: Vec = Vec::new(); let mut ni_vec: Vec> = Vec::new(); let mut j = 0; for i in 1..THRESHOLD + 2 { if i != party_num_int { let (m_b_gamma, beta_gamma, _, _) = MessageB::b( &sign_keys.gamma_i, &paillier_key_vector[usize::from(signers_vec[usize::from(i - 1)])], m_a_vec[j].clone(), &[], ) .unwrap(); let (m_b_w, beta_wi, _, _) = MessageB::b( &sign_keys.w_i, &paillier_key_vector[usize::from(signers_vec[usize::from(i - 1)])], m_a_vec[j].clone(), &[], ) .unwrap(); m_b_gamma_send_vec.push(m_b_gamma); m_b_w_send_vec.push(m_b_w); beta_vec.push(beta_gamma); ni_vec.push(beta_wi); j += 1; } } let mut j = 0; for i in 1..THRESHOLD + 2 { if i != party_num_int { assert!(sendp2p( &client, party_num_int, i, "round2", serde_json::to_string(&(m_b_gamma_send_vec[j].clone(), m_b_w_send_vec[j].clone())) .unwrap(), uuid.clone() ) .is_ok()); j += 1; } } let round2_ans_vec = poll_for_p2p( &client, party_num_int, THRESHOLD + 1, delay, "round2", uuid.clone(), ); let mut m_b_gamma_rec_vec: Vec = Vec::new(); let mut m_b_w_rec_vec: Vec = Vec::new(); for i in 0..THRESHOLD { // if signers_vec.contains(&(i as usize)) { let (m_b_gamma_i, m_b_w_i): (MessageB, MessageB) = serde_json::from_str(&round2_ans_vec[i as usize]).unwrap(); m_b_gamma_rec_vec.push(m_b_gamma_i); m_b_w_rec_vec.push(m_b_w_i); // } } let mut alpha_vec: Vec> = Vec::new(); let mut miu_vec: Vec> = Vec::new(); let mut j = 0; for i in 1..THRESHOLD + 2 { if i != party_num_int { let m_b = m_b_gamma_rec_vec[j].clone(); let alpha_ij_gamma = m_b .verify_proofs_get_alpha(&party_keys.dk, &sign_keys.k_i) .expect("wrong dlog or m_b"); let m_b = m_b_w_rec_vec[j].clone(); let alpha_ij_wi = m_b .verify_proofs_get_alpha(&party_keys.dk, &sign_keys.k_i) .expect("wrong dlog or m_b"); alpha_vec.push(alpha_ij_gamma.0); miu_vec.push(alpha_ij_wi.0); let g_w_i = Keys::update_commitments_to_xi( &xi_com_vec[usize::from(signers_vec[usize::from(i - 1)])], &vss_scheme_vec[usize::from(signers_vec[usize::from(i - 1)])], signers_vec[usize::from(i - 1)], &signers_vec, ); assert_eq!(m_b.b_proof.pk, g_w_i); j += 1; } } ////////////////////////////////////////////////////////////////////////////// let delta_i = sign_keys.phase2_delta_i(&alpha_vec, &beta_vec); let sigma = sign_keys.phase2_sigma_i(&miu_vec, &ni_vec); assert!(broadcast( &client, party_num_int, "round3", serde_json::to_string(&delta_i).unwrap(), uuid.clone() ) .is_ok()); let round3_ans_vec = poll_for_broadcasts( &client, party_num_int, THRESHOLD + 1, delay, "round3", uuid.clone(), ); let mut delta_vec: Vec> = Vec::new(); format_vec_from_reads( &round3_ans_vec, party_num_int as usize, delta_i, &mut delta_vec, ); let delta_inv = SignKeys::phase3_reconstruct_delta(&delta_vec); ////////////////////////////////////////////////////////////////////////////// // decommit to gamma_i assert!(broadcast( &client, party_num_int, "round4", serde_json::to_string(&decommit).unwrap(), uuid.clone() ) .is_ok()); let round4_ans_vec = poll_for_broadcasts( &client, party_num_int, THRESHOLD + 1, delay, "round4", uuid.clone(), ); let mut decommit_vec: Vec = Vec::new(); format_vec_from_reads( &round4_ans_vec, party_num_int as usize, decommit, &mut decommit_vec, ); let decomm_i = decommit_vec.remove(usize::from(party_num_int - 1)); bc1_vec.remove(usize::from(party_num_int - 1)); let b_proof_vec = (0..m_b_gamma_rec_vec.len()) .map(|i| &m_b_gamma_rec_vec[i].b_proof) .collect::>>(); let R = SignKeys::phase4(&delta_inv, &b_proof_vec, decommit_vec, &bc1_vec) .expect("bad gamma_i decommit"); // adding local g_gamma_i let R = R + decomm_i.g_gamma_i * delta_inv; // we assume the message is already hashed (by the signer). let message_bn = BigInt::from_bytes(message); let local_sig = LocalSignature::phase5_local_sig(&sign_keys.k_i, &message_bn, &R, &sigma, &y_sum); let (phase5_com, phase_5a_decom, helgamal_proof, dlog_proof_rho) = local_sig.phase5a_broadcast_5b_zkproof(); //phase (5A) broadcast commit assert!(broadcast( &client, party_num_int, "round5", serde_json::to_string(&phase5_com).unwrap(), uuid.clone() ) .is_ok()); let round5_ans_vec = poll_for_broadcasts( &client, party_num_int, THRESHOLD + 1, delay, "round5", uuid.clone(), ); let mut commit5a_vec: Vec = Vec::new(); format_vec_from_reads( &round5_ans_vec, party_num_int as usize, phase5_com, &mut commit5a_vec, ); //phase (5B) broadcast decommit and (5B) ZK proof assert!(broadcast( &client, party_num_int, "round6", serde_json::to_string(&( phase_5a_decom.clone(), helgamal_proof.clone(), dlog_proof_rho.clone() )) .unwrap(), uuid.clone() ) .is_ok()); let round6_ans_vec = poll_for_broadcasts( &client, party_num_int, THRESHOLD + 1, delay, "round6", uuid.clone(), ); let mut decommit5a_and_elgamal_and_dlog_vec: Vec<( Phase5ADecom1, HomoELGamalProof, DLogProof, )> = Vec::new(); format_vec_from_reads( &round6_ans_vec, party_num_int as usize, (phase_5a_decom.clone(), helgamal_proof, dlog_proof_rho), &mut decommit5a_and_elgamal_and_dlog_vec, ); let decommit5a_and_elgamal_and_dlog_vec_includes_i = decommit5a_and_elgamal_and_dlog_vec.clone(); decommit5a_and_elgamal_and_dlog_vec.remove(usize::from(party_num_int - 1)); commit5a_vec.remove(usize::from(party_num_int - 1)); let phase_5a_decomm_vec = (0..THRESHOLD) .map(|i| decommit5a_and_elgamal_and_dlog_vec[i as usize].0.clone()) .collect::>(); let phase_5a_elgamal_vec = (0..THRESHOLD) .map(|i| decommit5a_and_elgamal_and_dlog_vec[i as usize].1.clone()) .collect::>>(); let phase_5a_dlog_vec = (0..THRESHOLD) .map(|i| decommit5a_and_elgamal_and_dlog_vec[i as usize].2.clone()) .collect::>>(); let (phase5_com2, phase_5d_decom2) = local_sig .phase5c( &phase_5a_decomm_vec, &commit5a_vec, &phase_5a_elgamal_vec, &phase_5a_dlog_vec, &phase_5a_decom.V_i, &R, ) .expect("error phase5"); ////////////////////////////////////////////////////////////////////////////// assert!(broadcast( &client, party_num_int, "round7", serde_json::to_string(&phase5_com2).unwrap(), uuid.clone() ) .is_ok()); let round7_ans_vec = poll_for_broadcasts( &client, party_num_int, THRESHOLD + 1, delay, "round7", uuid.clone(), ); let mut commit5c_vec: Vec = Vec::new(); format_vec_from_reads( &round7_ans_vec, party_num_int as usize, phase5_com2, &mut commit5c_vec, ); //phase (5B) broadcast decommit and (5B) ZK proof assert!(broadcast( &client, party_num_int, "round8", serde_json::to_string(&phase_5d_decom2).unwrap(), uuid.clone() ) .is_ok()); let round8_ans_vec = poll_for_broadcasts( &client, party_num_int, THRESHOLD + 1, delay, "round8", uuid.clone(), ); let mut decommit5d_vec: Vec = Vec::new(); format_vec_from_reads( &round8_ans_vec, party_num_int as usize, phase_5d_decom2, &mut decommit5d_vec, ); let phase_5a_decomm_vec_includes_i = (0..=THRESHOLD) .map(|i| { decommit5a_and_elgamal_and_dlog_vec_includes_i[i as usize] .0 .clone() }) .collect::>(); let s_i = local_sig .phase5d( &decommit5d_vec, &commit5c_vec, &phase_5a_decomm_vec_includes_i, ) .expect("bad com 5d"); ////////////////////////////////////////////////////////////////////////////// assert!(broadcast( &client, party_num_int, "round9", serde_json::to_string(&s_i).unwrap(), uuid.clone() ) .is_ok()); let round9_ans_vec = poll_for_broadcasts(&client, party_num_int, THRESHOLD + 1, delay, "round9", uuid); let mut s_i_vec: Vec> = Vec::new(); format_vec_from_reads(&round9_ans_vec, party_num_int as usize, s_i, &mut s_i_vec); s_i_vec.remove(usize::from(party_num_int - 1)); let sig = local_sig .output_signature(&s_i_vec) .expect("verification failed"); println!("party {:?} Output Signature: \n", party_num_int); println!("R: {:?}", sig.r); println!("s: {:?} \n", sig.s); println!("recid: {:?} \n", sig.recid.clone()); let sign_json = serde_json::to_string(&( "r", BigInt::from_bytes(sig.r.to_bytes().as_ref()).to_str_radix(16), "s", BigInt::from_bytes(sig.s.to_bytes().as_ref()).to_str_radix(16), )) .unwrap(); // check sig against secp256k1 check_sig(&sig.r, &sig.s, &message_bn, &y_sum); fs::write("signature".to_string(), sign_json).expect("Unable to save !"); } fn format_vec_from_reads<'a, T: serde::Deserialize<'a> + Clone>( ans_vec: &'a [String], party_num: usize, value_i: T, new_vec: &'a mut Vec, ) { let mut j = 0; for i in 1..ans_vec.len() + 2 { if i == party_num { new_vec.push(value_i.clone()); } else { let value_j: T = serde_json::from_str(&ans_vec[j]).unwrap(); new_vec.push(value_j); j += 1; } } } pub fn signup(client: &Client) -> Result { let key = "signup-sign".to_string(); let res_body = postb(client, "signupsign", key).unwrap(); serde_json::from_str(&res_body).unwrap() }