├── .gitignore ├── LICENSE ├── README.md ├── RelayProofsOfConcept ├── EddsaRocketServer │ ├── pg-eddsa-client │ │ ├── Cargo.toml │ │ └── src │ │ │ └── main.rs │ └── rocket-server │ │ ├── Cargo.toml │ │ ├── Rocket.toml │ │ └── src │ │ └── main.rs ├── EddsaTendermintServer │ ├── .gitignore │ ├── Cargo.toml │ ├── Makefile │ ├── README.md │ ├── demo │ │ └── tendermint-demo.gif │ ├── generate.py │ ├── kg-demo.sh │ ├── mmpc-client │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── bin │ │ │ ├── kg-client.rs │ │ │ └── sign-client.rs │ │ │ ├── eddsa_peer_kg.rs │ │ │ ├── eddsa_peer_sign.rs │ │ │ ├── lib.rs │ │ │ ├── peer.rs │ │ │ └── tendermint_client.rs │ ├── mmpc-server-common │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── common.rs │ │ │ ├── lib.rs │ │ │ └── protocol.rs │ ├── protocols.json │ ├── run_exp.py │ ├── sign-demo.sh │ ├── src │ │ ├── bin │ │ │ └── server.rs │ │ ├── lib.rs │ │ ├── messages.json │ │ ├── relay_app.rs │ │ └── relay_session.rs │ ├── tests │ │ └── test_relay_server.rs │ ├── tools │ │ ├── kg-demo.sh │ │ └── sign-demo.sh │ └── use-cases.md ├── EddsaTokioServer │ ├── .gitignore │ ├── Cargo.toml │ ├── README.md │ ├── demo │ │ └── 2P-EdDSA demo.gif │ ├── examples │ │ ├── connect.rs │ │ ├── eddsa_key_gen_client.rs │ │ └── eddsa_sign_client.rs │ ├── keygen.sh │ ├── protocols.json │ ├── relay-server-common │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── common.rs │ │ │ ├── lib.rs │ │ │ └── protocol.rs │ ├── relay-server.iml │ ├── sign.sh │ ├── src │ │ ├── bin │ │ │ └── server.rs │ │ ├── lib.rs │ │ ├── messages.json │ │ ├── relay_server.rs │ │ └── relay_session.rs │ └── tests │ │ └── test_relay_server.rs ├── Formal-spec │ ├── TLA+ │ │ ├── RelayServer.pdf │ │ └── RelayServer.tla │ └── coq │ │ ├── Makefile │ │ ├── README.md │ │ ├── relayserver.pdf │ │ ├── relayserver.v │ │ └── subset.v └── README.md └── White-City-Report ├── white_city.pdf └── whitecity_new.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | .idea 13 | .DS_Store 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # white-city 2 | API to integrate distributed network for secure computation protocols. 3 | 4 | Read more details in our technical report: 5 | [White-City](./White-City-Report/whitecity_new.pdf) 6 | 7 | ### Background 8 | Secure Multiparty Computation (MPC) has transitioned from a thoretical field to applied technology with real life use cases. In MPC a set of n parties are running a distributed computation over private inputs. To do so, MPC protocols designers make assumptions on the required network and communication channels. A complete p2p network setup might turn out to be costly, effectively eliminating the practicallity of running MPC at scale. 9 | 10 | Instead, we suggest using untrusted coordinator, connected in a star topology to all clients. This gets us immidiate improvment on communication complexity of simple p2p, and potentially benefits robustness, accountabillity and fault tolarance. 11 | 12 | 13 | ### Project Status: 14 | The current stage is focused on the idea of replicated state machine. The repo contains three proofs of concepts. 15 | The latest implementation uses Tendermint to replicate the state machine across a set of known servers. 16 | Clients broadcast transactions to the servers to change the state, and read messages from the public bulletin board. Older PoCs are using a single untrusted coordinator. 17 | 18 | - **[Tendermint](https://github.com/KZen-networks/white-city/tree/master/RelayProofsOfConcept/EddsaTendermintServer):** Broadcast channel using Tendermint as an immutable bulletin board. 19 | - **[TokioServer](https://github.com/KZen-networks/white-city/tree/master/RelayProofsOfConcept/EddsaTokioServer):** a socket level implementation using Tokio Crate. 20 | - **[RocketServer](https://github.com/KZen-networks/white-city/tree/master/RelayProofsOfConcept/EddsaRocketServer):** a Http server implementation using Rocket crate. 21 | Proofs of concept are currently running [multi party EdDSA](https://github.com/KZen-networks/multi-party-eddsa) library. In general, all messages in the MPC protocol should be broadcast messages (p2p messages are broadcasted encrypted). 22 | 23 | As a side project there is also an effort to formally verify the centralized state machine model in [Coq/TLA+](https://github.com/KZen-networks/white-city/tree/master/RelayProofsOfConcept/Formal-spec) 24 | 25 | ### Hall of Fame: 26 | Here is a list of contributors to White City (not ordered): 27 | - Avi Kozokin 28 | - Alex Manuskin 29 | - Frederic Peschanski 30 | - Omer Shlomovits 31 | - Roman Zeyde 32 | - Haoyu LIN 33 | 34 | 35 | ### Want to Contribute: 36 | Please send an email to github@kzencorp.com containing your github username. We will get in touch and bring you up to speed. We try to keep the list of issues relevant so it might also be a good place to start. Join the ZenGo X [Telegram](https://t.me/joinchat/ET1mddGXRoyCxZ-7) for discussions on code and research. 37 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaRocketServer/pg-eddsa-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pg-eddsa-client" 3 | version = "0.1.0" 4 | authors = ["omershlo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | serde = "1.0" 9 | serde_json = "1.0" 10 | serde_derive = "1.0" 11 | 12 | reqwest = "0.9.5" 13 | 14 | [dependencies.multi-party-ed25519] 15 | git = "https://github.com/KZen-networks/multi-party-eddsa" 16 | 17 | [dependencies.curv] 18 | git = "https://github.com/KZen-networks/curv" 19 | features = ["ed25519"] -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaRocketServer/pg-eddsa-client/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | extern crate curv; 4 | /// to run: 5 | /// 1: go to rocket_server -> cargo run 6 | /// 2: cargo run from PARTIES number of terminals 7 | extern crate multi_party_ed25519; 8 | extern crate reqwest; 9 | #[macro_use] 10 | extern crate serde_derive; 11 | 12 | #[macro_use] 13 | extern crate serde_json; 14 | 15 | use curv::elliptic::curves::traits::ECScalar; 16 | use curv::{BigInt, FE, GE}; 17 | use multi_party_ed25519::protocols::aggsig::*; 18 | use reqwest::Client; 19 | use std::env; 20 | use std::fmt; 21 | use std::time::Duration; 22 | use std::{thread, time}; 23 | 24 | const PARTIES: u32 = 4; 25 | 26 | #[derive(Hash, PartialEq, Eq, Clone, Debug, Serialize, Deserialize)] 27 | pub struct TupleKey { 28 | pub first: String, 29 | pub second: String, 30 | pub third: String, 31 | } 32 | impl TupleKey { 33 | fn new(first: String, second: String, third: String) -> TupleKey { 34 | return TupleKey { 35 | first, 36 | second, 37 | third, 38 | }; 39 | } 40 | } 41 | fn pr(x: &String) { 42 | println!("{:?}", &*x); 43 | } 44 | impl fmt::Display for TupleKey { 45 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 46 | write!(f, "({}, {}, {})", self.first, self.second, self.third) 47 | } 48 | } 49 | 50 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 51 | pub struct PartySignup { 52 | pub number: u32, 53 | pub uuid: String, 54 | } 55 | 56 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 57 | pub struct Index { 58 | pub key: TupleKey, 59 | } 60 | 61 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 62 | pub struct Entry { 63 | pub key: TupleKey, 64 | pub value: String, 65 | } 66 | 67 | fn main() { 68 | // working with ed25519 communication we make sure we are in the prime sub group 69 | let eight_bn = BigInt::from(8); 70 | let eight: FE = ECScalar::from(&eight_bn); 71 | let eight_inv = eight.invert(); 72 | // delay: 73 | let ten_millis = time::Duration::from_millis(10); 74 | 75 | let message: [u8; 4] = [79, 77, 69, 82]; //TODO: make arg 76 | let client = Client::new(); 77 | 78 | let party_i_signup_result = signup(&client); 79 | 80 | assert!(party_i_signup_result.is_ok()); 81 | let party_i_signup = party_i_signup_result.unwrap(); 82 | println!("{:?}", party_i_signup.clone()); 83 | 84 | let party_num_int = party_i_signup.number.clone(); 85 | let uuid = party_i_signup.uuid; 86 | ////////////////////////////////////////////////////////////////////////////// 87 | 88 | let party_key = KeyPair::create(); 89 | let (party_ephemeral_key, sign_first_message, sign_second_message) = 90 | Signature::create_ephemeral_key_and_commit(&party_key, &message); 91 | ////////////////////////////////////////////////////////////////////////////// 92 | 93 | //round 0: send public key, get public keys from other parties (the protocol is not specifying anything on how to share pubkeys) 94 | assert!(send( 95 | &client, 96 | party_num_int.clone(), 97 | "round0", 98 | serde_json::to_string(&party_key.public_key).unwrap(), 99 | uuid.clone() 100 | ) 101 | .is_ok()); 102 | let round0_ans_vec = poll_for_peers( 103 | &client, 104 | party_num_int.clone(), 105 | PARTIES, 106 | ten_millis.clone(), 107 | "round0", 108 | uuid.clone(), 109 | ); 110 | 111 | ////////////////////////////////////////////////////////////////////////////// 112 | //compute apk: 113 | let mut j = 0; 114 | let mut pks: Vec = Vec::new(); 115 | for i in 1..PARTIES + 1 { 116 | if i == party_num_int { 117 | pks.push(&party_key.public_key * &eight); 118 | } else { 119 | let party_i_pubkey: GE = serde_json::from_str(&round0_ans_vec[j]).unwrap(); 120 | pks.push(party_i_pubkey); 121 | j = j + 1; 122 | } 123 | } 124 | let partyi_key_agg = KeyPair::key_aggregation_n(&pks, &(party_num_int as usize - 1)); 125 | ////////////////////////////////////////////////////////////////////////////// 126 | 127 | // send commitment to ephemeral public keys, get round 1 commitments of other parties 128 | assert!(send( 129 | &client, 130 | party_num_int.clone(), 131 | "round1", 132 | serde_json::to_string(&sign_first_message).unwrap(), 133 | uuid.clone() 134 | ) 135 | .is_ok()); 136 | let round1_ans_vec = poll_for_peers( 137 | &client, 138 | party_num_int.clone(), 139 | PARTIES, 140 | ten_millis.clone(), 141 | "round1", 142 | uuid.clone(), 143 | ); 144 | 145 | // round 2: send ephemeral public keys and check commitments correctness 146 | assert!(send( 147 | &client, 148 | party_num_int.clone(), 149 | "round2", 150 | serde_json::to_string(&sign_second_message).unwrap(), 151 | uuid.clone() 152 | ) 153 | .is_ok()); 154 | let round2_ans_vec = poll_for_peers( 155 | &client, 156 | party_num_int.clone(), 157 | PARTIES, 158 | ten_millis.clone(), 159 | "round2", 160 | uuid.clone(), 161 | ); 162 | 163 | ////////////////////////////////////////////////////////////////////////////// 164 | // test commitments and construct R 165 | let mut Ri: Vec = Vec::new(); 166 | let mut j = 0; 167 | for i in 1..PARTIES + 1 { 168 | if i != party_num_int { 169 | let party_i_first_message: SignFirstMsg = 170 | serde_json::from_str(&round1_ans_vec[j]).unwrap(); 171 | let party_i_second_message: SignSecondMsg = 172 | serde_json::from_str(&round2_ans_vec[j]).unwrap(); 173 | let R_inv_eight = &party_i_second_message.R * &eight_inv; 174 | assert!(test_com( 175 | &R_inv_eight, 176 | &party_i_second_message.blind_factor, 177 | &party_i_first_message.commitment 178 | )); 179 | Ri.push(party_i_second_message.R); 180 | println!("party {:?} comm is valid", i); 181 | j = j + 1; 182 | } else { 183 | Ri.push(&party_ephemeral_key.R * &eight); 184 | } 185 | } 186 | // calculate local signature: 187 | let R_tot = Signature::get_R_tot(Ri); 188 | let k = Signature::k(&R_tot, &partyi_key_agg.apk, &message); 189 | let si = Signature::partial_sign( 190 | &party_ephemeral_key.r, 191 | &party_key, 192 | &k, 193 | &partyi_key_agg.hash, 194 | &R_tot, 195 | ); 196 | 197 | ////////////////////////////////////////////////////////////////////////////// 198 | 199 | // round 3: send ephemeral public keys and check commitments correctness 200 | assert!(send( 201 | &client, 202 | party_num_int.clone(), 203 | "round3", 204 | serde_json::to_string(&si).unwrap(), 205 | uuid.clone() 206 | ) 207 | .is_ok()); 208 | let round3_ans_vec = poll_for_peers( 209 | &client, 210 | party_num_int.clone(), 211 | PARTIES, 212 | ten_millis.clone(), 213 | "round3", 214 | uuid.clone(), 215 | ); 216 | 217 | ////////////////////////////////////////////////////////////////////////////// 218 | 219 | // compute signature: 220 | let mut j = 0; 221 | let mut s: Vec = Vec::new(); 222 | for i in 1..PARTIES + 1 { 223 | if i == party_num_int { 224 | s.push(Signature { 225 | R: R_tot.clone(), 226 | s: si.s.clone() * &eight, 227 | }); 228 | } else { 229 | let party_i_si: Signature = serde_json::from_str(&round3_ans_vec[j]).unwrap(); 230 | let party_i_si = Signature { 231 | R: R_tot.clone(), 232 | s: party_i_si.s * &eight, 233 | }; //same R for all partial sigs. TODO: send only s part of the partial sigs? 234 | s.push(party_i_si); 235 | j = j + 1; 236 | } 237 | } 238 | 239 | let signature = Signature::add_signature_parts(s); 240 | assert!(verify(&signature, &message, &partyi_key_agg.apk).is_ok()); 241 | println!(" {:?} \n on message : {:?}", signature, message); 242 | ////////////////////////////////////////////////////////////////////////////// 243 | } 244 | 245 | pub fn postb(client: &Client, path: &str, body: T) -> Option 246 | where 247 | T: serde::ser::Serialize, 248 | { 249 | let res = client 250 | .post(&format!("http://127.0.0.1:8001/{}", path)) 251 | .json(&body) 252 | .send(); 253 | Some(res.unwrap().text().unwrap()) 254 | } 255 | 256 | pub fn signup(client: &Client) -> Result<(PartySignup), ()> { 257 | let key = TupleKey { 258 | first: "signup".to_string(), 259 | second: "".to_string(), 260 | third: "".to_string(), 261 | }; 262 | 263 | let res_body = postb(&client, "signup", key).unwrap(); 264 | let answer: Result<(PartySignup), ()> = serde_json::from_str(&res_body).unwrap(); 265 | return answer; 266 | } 267 | 268 | pub fn send( 269 | client: &Client, 270 | party_num: u32, 271 | round: &str, 272 | data: String, 273 | uuid: String, 274 | ) -> Result<(), ()> { 275 | let key = TupleKey { 276 | first: party_num.to_string(), 277 | second: round.to_string(), 278 | third: uuid, 279 | }; 280 | let entry = Entry { 281 | key: key.clone(), 282 | value: data, 283 | }; 284 | 285 | let res_body = postb(&client, "set", entry).unwrap(); 286 | let answer: Result<(), ()> = serde_json::from_str(&res_body).unwrap(); 287 | return answer; 288 | } 289 | 290 | pub fn poll_for_peers( 291 | client: &Client, 292 | party_num: u32, 293 | n: u32, 294 | delay: Duration, 295 | round: &str, 296 | uuid: String, 297 | ) -> Vec { 298 | let mut ans_vec = Vec::new(); 299 | for i in 1..n + 1 { 300 | if i != party_num { 301 | let key = TupleKey { 302 | first: i.to_string(), 303 | second: round.to_string(), 304 | third: uuid.clone(), 305 | }; 306 | let index = Index { key }; 307 | loop { 308 | // add delay to allow the server to process request: 309 | thread::sleep(delay); 310 | let res_body = postb(client, "get", index.clone()).unwrap(); 311 | let answer: Result = serde_json::from_str(&res_body).unwrap(); 312 | if answer.is_ok() { 313 | ans_vec.push(answer.unwrap().value); 314 | println!("party {:?} {:?} read success", i, round); 315 | break; 316 | } 317 | } 318 | } 319 | } 320 | ans_vec 321 | } 322 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaRocketServer/rocket-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rocket_server" 3 | version = "0.1.0" 4 | authors = ["omershlo "] 5 | edition = "2018" 6 | 7 | 8 | 9 | [dependencies] 10 | rocket = "0.4.0" 11 | rocket_contrib = "0.4.0" 12 | 13 | serde = "1.0" 14 | serde_json = "1.0" 15 | serde_derive = "1.0" 16 | 17 | reqwest = "0.9.5" 18 | uuid = { version = "0.7", features = ["v4"] } -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaRocketServer/rocket-server/Rocket.toml: -------------------------------------------------------------------------------- 1 | [development] 2 | address = "127.0.0.1" 3 | port = 8001 4 | workers = 12 5 | keep_alive = 5 6 | log = "normal" 7 | hi = "Hello!" # this is an unused extra; maybe application specific? 8 | is_extra = true # this is an unused extra; maybe application specific? 9 | 10 | [staging] 11 | address = "0.0.0.0" 12 | port = 8000 13 | workers = 8 14 | keep_alive = 5 15 | log = "normal" 16 | # don't use this key! generate your own and keep it private! 17 | secret_key = "8Xui8SN4mI+7egV/9dlfYYLGQJeEx4+DwmSQLwDVXJg=" 18 | 19 | [production] 20 | address = "0.0.0.0" 21 | port = 8000 22 | workers = 12 23 | keep_alive = 5 24 | log = "critical" 25 | # don't use this key! generate your own and keep it private! 26 | secret_key = "hPRYyVRiMyxpw5sBB1XeCMN1kFsDCqKvBi2QJxBVHQk=" -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaRocketServer/rocket-server/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene, decl_macro)] 2 | 3 | #[macro_use] 4 | extern crate rocket; 5 | 6 | extern crate reqwest; 7 | extern crate rocket_contrib; 8 | extern crate uuid; 9 | 10 | #[macro_use] 11 | extern crate serde_derive; 12 | extern crate serde; 13 | extern crate serde_json; 14 | 15 | use rocket::config::Config; 16 | use rocket::State; 17 | use rocket_contrib::json::Json; 18 | use std::collections::HashMap; 19 | use std::fmt; 20 | use std::str; 21 | use std::sync::RwLock; 22 | use uuid::Uuid; 23 | 24 | const PARTIES: u32 = 4; 25 | 26 | #[derive(Hash, PartialEq, Eq, Clone, Debug, Serialize, Deserialize)] 27 | pub struct TupleKey { 28 | pub first: String, 29 | pub second: String, 30 | pub third: String, 31 | } 32 | impl TupleKey { 33 | fn new(first: String, second: String, third: String) -> TupleKey { 34 | return TupleKey { 35 | first, 36 | second, 37 | third, 38 | }; 39 | } 40 | } 41 | fn pr(x: &String) { 42 | println!("{:?}", &*x); 43 | } 44 | impl fmt::Display for TupleKey { 45 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 46 | write!(f, "({}, {}, {})", self.first, self.second, self.third) 47 | } 48 | } 49 | 50 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 51 | pub struct PartySignup { 52 | pub number: u32, 53 | pub uuid: String, 54 | } 55 | 56 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 57 | pub struct Index { 58 | pub key: TupleKey, 59 | } 60 | 61 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 62 | pub struct Entry { 63 | pub key: TupleKey, 64 | pub value: String, 65 | } 66 | #[post("/get", format = "json", data = "")] 67 | fn get( 68 | db_mtx: State>>, 69 | request: Json, 70 | ) -> Json> { 71 | let index: Index = request.0; 72 | let hm = db_mtx.read().unwrap(); 73 | match hm.get(&index.key) { 74 | Some(v) => { 75 | let entry = Entry { 76 | key: index.key, 77 | value: format!("{}", v.clone()), 78 | }; 79 | Json(Ok(entry)) 80 | } 81 | None => Json(Err(())), 82 | } 83 | } 84 | 85 | #[post("/set", format = "json", data = "")] 86 | fn set( 87 | db_mtx: State>>, 88 | request: Json, 89 | ) -> Json> { 90 | let entry: Entry = request.0; 91 | let mut hm = db_mtx.write().unwrap(); 92 | hm.insert(entry.key.clone(), entry.value.clone()); 93 | Json(Ok(())) 94 | } 95 | 96 | #[post("/signup", format = "json")] 97 | fn signup(db_mtx: State>>) -> Json> { 98 | let key = TupleKey { 99 | first: "signup".to_string(), 100 | second: "".to_string(), 101 | third: "".to_string(), 102 | }; 103 | let mut hm = db_mtx.read().unwrap(); 104 | match hm.get(&key) { 105 | Some(value) => { 106 | let party_i_minus1_signup: PartySignup = serde_json::from_str(&value).unwrap(); 107 | if party_i_minus1_signup.number < PARTIES { 108 | let party_num = party_i_minus1_signup.number + 1; 109 | let party_signup = PartySignup { 110 | number: party_num.clone(), 111 | uuid: party_i_minus1_signup.uuid, 112 | }; 113 | // update state: 114 | drop(hm); 115 | let mut hm = db_mtx.write().unwrap(); 116 | hm.insert(key, serde_json::to_string(&party_signup).unwrap()); 117 | return Json(Ok(party_signup)); 118 | } 119 | } 120 | None => {} 121 | } 122 | // start new session 123 | 124 | let uuid = Uuid::new_v4().to_string(); 125 | let party1 = 1; 126 | let party_signup = PartySignup { 127 | number: party1, 128 | uuid, 129 | }; 130 | 131 | // update state: 132 | drop(hm); 133 | let mut hm = db_mtx.write().unwrap(); 134 | hm.insert(key, serde_json::to_string(&party_signup).unwrap()); 135 | 136 | Json(Ok(party_signup)) 137 | } 138 | 139 | //refcell, arc 140 | 141 | fn main() { 142 | // let mut my_config = Config::development(); 143 | // my_config.set_port(18001); 144 | let db: HashMap = HashMap::new(); 145 | let db_mtx = RwLock::new(db); 146 | //rocket::custom(my_config).mount("/", routes![get, set]).manage(db_mtx).launch(); 147 | rocket::ignite() 148 | .mount("/", routes![get, set, signup]) 149 | .manage(db_mtx) 150 | .launch(); 151 | } 152 | 153 | pub mod tests { 154 | use super::{Entry, Index, TupleKey}; 155 | use reqwest; 156 | use serde_json; 157 | 158 | #[test] 159 | pub fn simple_set_get() { 160 | let client = reqwest::Client::new(); 161 | 162 | let key = TupleKey { 163 | first: "omer".to_string(), 164 | second: "shlomovits".to_string(), 165 | third: "".to_string(), 166 | }; 167 | let entry = Entry { 168 | key: key.clone(), 169 | value: "secret".to_string(), 170 | }; 171 | let res_body = postb(&client, "set", entry).unwrap(); 172 | let answer1: Result<(), ()> = serde_json::from_str(&res_body).unwrap(); 173 | println!("answer1: {:?}", answer1); 174 | 175 | let index = Index { key }; 176 | let res_body = postb(&client, "get", index).unwrap(); 177 | let answer2: Result = serde_json::from_str(&res_body).unwrap(); 178 | println!("answer2: {:?}", answer2); 179 | } 180 | 181 | pub fn postb(client: &reqwest::Client, path: &str, body: T) -> Option 182 | where 183 | T: serde::ser::Serialize, 184 | { 185 | let res = client 186 | .post(&format!("http://localhost:8001/{}", path)) 187 | .json(&body) 188 | .send(); 189 | Some(res.unwrap().text().unwrap()) 190 | } 191 | 192 | } 193 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | */target/ 4 | /target/ 5 | common/target/ 6 | 7 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 8 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 9 | Cargo.lock 10 | 11 | # These are backup files generated by rustfmt 12 | **/*.rs.bk 13 | .*.swp 14 | 15 | 16 | # IDE 17 | .idea 18 | .DS_Store 19 | .vscode/ 20 | *rusty-tags.vi 21 | */rusty-tags.vi 22 | 23 | tools/local-cluster-*.sh 24 | full-exp* 25 | 26 | *.csv 27 | 28 | keys* 29 | signature* 30 | 31 | # Log files 32 | *.log 33 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "mmpc-server-common", 4 | "mmpc-client" 5 | ] 6 | 7 | [package] 8 | name = "mmpc-server" 9 | version = "0.1.0" 10 | authors = ["Avi ", "Alex Manuskin "] 11 | edition = "2018" 12 | 13 | [dependencies] 14 | chrono = "0.4" 15 | log = "0.4" 16 | clap = "2.33" 17 | fern = "0.5" 18 | hex = "0.3.2" 19 | serde = { version = "1.0", features = ["derive"] } 20 | serde_json = "1.0" 21 | subtle-encoding = { version = "0.3", features = ["bech32-preview"] } 22 | better-panic = "0.1.2" 23 | 24 | mmpc-server-common = { path = "./mmpc-server-common" } 25 | 26 | [dependencies.multi-party-eddsa] 27 | git = "https://github.com/KZen-networks/multi-party-eddsa" 28 | tag = "v0.2.1" 29 | 30 | [dependencies.curv] 31 | git = "https://github.com/KZen-networks/curv" 32 | tag = "v0.2.0-ed25519" 33 | features=["ec_ed25519"] 34 | 35 | [dependencies.abci] 36 | git="https://github.com/tendermint/rust-abci" 37 | branch="develop" 38 | 39 | [dependencies.tendermint] 40 | version = "0.10.0" 41 | git="https://github.com/amanusk/tendermint-rs" 42 | branch = "develop" 43 | features = ["rpc"] 44 | 45 | [lib] 46 | name = "mmpc_server" 47 | path = "src/lib.rs" 48 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | cargo build --all 3 | 4 | clean: 5 | rm log*.log 6 | rm relay-server*.log 7 | rm keys* 8 | rm signature* 9 | 10 | clean-exp: 11 | rm exp-kg* 12 | rm exp-sign* 13 | 14 | clean-all: clean clean-exp 15 | rm full-exp* 16 | 17 | kill: 18 | pgrep tendermint | xargs kill -KILL 19 | pgrep sign | xargs kill -KILL 20 | pgrep kg | xargs kill -KILL 21 | 22 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/README.md: -------------------------------------------------------------------------------- 1 | # White-City-Tendermint 2 | 3 | This is a POC for running distributed multi-party signatures with Tendermint consensus as a backend for message broadcast 4 | 5 | ## Build instructions: 6 | Build server and clients: 7 | `cargo build --all` 8 | 9 | ## Instructions: Tendermint cluster 10 | Instructions to run a full demo of distributed key generation and n-of-n signing 11 | 12 | ### Prerequisites: 13 | * `Tendermint`: Follow the installation guide for your system at [tendermint github](https://github.com/tendermint/tendermint) 14 | * `tmux` 15 | * `python` 16 | 17 | ### Instructions: 18 | The script `generate.py` takes the number of nodes as a parameter, and generates scripts to run a cluster of Tendermint nodes 19 | The shell scripts are created in a `./tools` directory. 4 Nodes is the default. 20 | 21 | 1. run `./tools/local-cluster-init.sh` to create a node Testnet configuration 22 | 2. run `./tools/local-cluster-start.sh` to start the Tendermint nodes, along with the application servers in separate `tmux` sessions 23 | 3. run `./tools/kg-demo.sh` to run key generation. By default, each client is communicating with a random node. 24 | The script takes 2 parameters, the first is the number of nodes (same as in `generate.py`) and the second is the number of participating parties 25 | For example, if at first `generate.py` was invoked with `python generate.py -n 4`, you can run `./tools/kg-demo.sh 4 12` for 4 nodes and 12 parties. 26 | 27 | At the moment, a reset is required after the key gen and before signing 28 | Reset the Tendermint cluster with 29 | 30 | `./tools/local-cluster-reset.sh` 31 | Then run the signing similarly to key generation, for example: 32 | `./tools/sign-demo.sh 4 12` for 4 nodes and 12 parties 33 | 34 | In the demo 5 clients create a threshold signature. A cluster of 4 nodes runs the protocol, after node 3 fails, the protocol still completes successfully. 35 | ![demo](./demo/tendermint-demo.gif) 36 | 37 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/demo/tendermint-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZenGo-X/white-city/eada16e95964fbaf23ca86e2251789bfa6e57bfd/RelayProofsOfConcept/EddsaTendermintServer/demo/tendermint-demo.gif -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/generate.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import stat 4 | 5 | HELP_MESSAGE = """ 6 | Config generator for experiments 7 | """ 8 | 9 | def create_init_file(nodes): 10 | init_file_name = './tools/local-cluster-init-{}.sh'.format(nodes) 11 | with open(init_file_name, 12 | 'w') as init_file: 13 | init_file.write('tendermint testnet --v {0} --o ~/.tendermint/cluster{0}/'.format(nodes)) 14 | st = os.stat(init_file_name) 15 | os.chmod(init_file_name, st.st_mode | stat.S_IEXEC) 16 | 17 | 18 | def create_start_file(nodes): 19 | def persisnent_peers(nodes): 20 | config_lines = list() 21 | p2p_port_start = 46056 22 | for node in range(nodes - 1): 23 | p2p_port = p2p_port_start + node * 100 24 | node_config = '$(tendermint show_node_id --home $HOME/.tendermint/cluster{0}/node0)"@127.0.0.1:{1},"\\'.format(nodes,p2p_port) 25 | config_lines.append(node_config + '\n') 26 | # Last line without \ 27 | p2p_port = p2p_port_start + (nodes - 1) * 100 28 | node_config = '$(tendermint show_node_id --home $HOME/.tendermint/cluster{0}/node0)"@127.0.0.1:{1}"'.format(nodes, p2p_port) 29 | config_lines.append(node_config + '\n') 30 | return config_lines 31 | 32 | def app_tmux_sessions(nodes): 33 | node_lines = list() 34 | proxy_address_base = 46058 35 | for node in range(nodes): 36 | proxy_port = proxy_address_base + node * 100 37 | line = 'tmux new -d -s app{0} && tmux send-keys -t app{0} "cargo run -- --address 127.0.0.1:{1}" C-m'.format(node, proxy_port) + '\n' 38 | node_lines.append(line) 39 | return node_lines 40 | 41 | def node_tmux_sessions(nodes): 42 | node_lines = list() 43 | proxy_address_base = 46058 44 | rpc_address_base = 46057 45 | p2p_address_base = 46056 46 | for node in range(nodes): 47 | proxy_port = proxy_address_base + node * 100 48 | rpc_port = rpc_address_base + node * 100 49 | p2p_port = p2p_address_base + node * 100 50 | line = 'tmux new -d -s node{0} && tmux send-keys -t node{0} "tendermint node --proxy_app tcp://127.0.0.1:{1} --rpc.laddr=tcp://0.0.0.0:{2} --home ~/.tendermint/cluster{3}/node{0} --consensus.create_empty_blocks=false --p2p.laddr=tcp://0.0.0.0:{4} --p2p.persistent_peers=$TM_PERSISTENT_PEERS" C-m'.format(node, proxy_port, rpc_port, nodes, p2p_port) + '\n' 51 | node_lines.append(line) 52 | return node_lines 53 | 54 | start_file_name = './tools/local-cluster-start-{}.sh'.format(nodes) 55 | with open(start_file_name, 56 | 'w') as start_file: 57 | start_file.write('CWD=`dirname $0`' + '\n') 58 | start_file.write('TM_PERSISTENT_PEERS=\\' + '\n') 59 | start_file.writelines(persisnent_peers(nodes)) 60 | start_file.writelines(app_tmux_sessions(nodes)) 61 | start_file.writelines(node_tmux_sessions(nodes)) 62 | st = os.stat(start_file_name) 63 | os.chmod(start_file_name, st.st_mode | stat.S_IEXEC) 64 | 65 | 66 | def create_stop_file(nodes): 67 | stop_file_name = './tools/local-cluster-stop-{}.sh'.format(nodes) 68 | with open(stop_file_name, 69 | 'w') as stop_file: 70 | for node in range(nodes): 71 | stop_file.write('tmux kill-session -t app{}'.format(node) + '\n') 72 | stop_file.write('tmux kill-session -t node{}'.format(node) + '\n') 73 | stop_file.write('pgrep tendermint | xargs kill -KILL') 74 | st = os.stat(stop_file_name) 75 | os.chmod(stop_file_name, st.st_mode | stat.S_IEXEC) 76 | 77 | def create_delete_file(nodes): 78 | delete_file_name = './tools/local-cluster-delete-{}.sh'.format(nodes) 79 | with open(delete_file_name, 80 | 'w') as delete_file: 81 | delete_file.write('CWD=`dirname $0`' + '\n') 82 | delete_file.write('$CWD/local-cluster-stop-{}.sh'.format(nodes) + '\n') 83 | delete_file.write('rm -rf ~/.tendermint/cluster{}'.format(nodes)) 84 | st = os.stat(delete_file_name) 85 | os.chmod(delete_file_name, st.st_mode | stat.S_IEXEC) 86 | 87 | 88 | def create_reset_file(nodes): 89 | reset_file_name = './tools/local-cluster-reset-{}.sh'.format(nodes) 90 | with open(reset_file_name, 'w') as reset_file: 91 | reset_file.write('CWD=`dirname $0`' + '\n') 92 | 93 | reset_file.write('$CWD/local-cluster-delete-{}.sh'.format(nodes) + '\n') 94 | reset_file.write('$CWD/local-cluster-init-{}.sh'.format(nodes) + '\n') 95 | reset_file.write('$CWD/local-cluster-start-{}.sh'.format(nodes) + '\n') 96 | st = os.stat(reset_file_name) 97 | os.chmod(reset_file_name, st.st_mode | stat.S_IEXEC) 98 | 99 | 100 | def main(): 101 | args = get_args() 102 | create_init_file(int(args.nodes)) 103 | create_start_file(int(args.nodes)) 104 | create_stop_file(int(args.nodes)) 105 | create_delete_file(args.nodes) 106 | create_reset_file(args.nodes) 107 | 108 | def get_args(): 109 | 110 | parser = argparse.ArgumentParser( 111 | description=HELP_MESSAGE, 112 | formatter_class=argparse.RawTextHelpFormatter) 113 | 114 | parser.add_argument('-d', '--debug', 115 | default=False, action='store_true', 116 | help="Output debug log to _s-tui.log") 117 | parser.add_argument('-n', '--nodes', 118 | default=4, 119 | help="Number of nodes to create configs for") 120 | args = parser.parse_args() 121 | return args 122 | 123 | 124 | if __name__ == '__main__': 125 | main() 126 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/kg-demo.sh: -------------------------------------------------------------------------------- 1 | echo "$0: MP-EDDSA" 2 | #clean 3 | 4 | rm keys* 5 | rm log-kg*.log 6 | rm log-error*.log 7 | 8 | n=3 9 | 10 | echo "keygen part" 11 | for i in $(seq 1 $n); 12 | do 13 | #cargo run -p mmpc-client --bin kg-client -- -I $i --capacity $n -v & 14 | cargo run -p mmpc-client --bin kg-client -- -I $i --capacity $n & 15 | done 16 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/mmpc-client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mmpc-client" 3 | version = "0.1.0" 4 | authors = ["amanusk "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | chrono = "0.4" 11 | log = "0.4" 12 | clap = "2.33" 13 | fern = "0.5" 14 | hex = "0.3.2" 15 | serde = { version = "1.0", features = ["derive"] } 16 | serde_json = "1.0" 17 | subtle-encoding = { version = "0.3", features = ["bech32-preview"] } 18 | better-panic = "0.1.2" 19 | time= "0.1.42" 20 | csv = "1.1.1" 21 | 22 | mmpc-server-common = { path = "../mmpc-server-common" } 23 | 24 | [dependencies.multi-party-eddsa] 25 | git = "https://github.com/KZen-networks/multi-party-eddsa" 26 | tag = "v0.2.1" 27 | 28 | [dependencies.curv] 29 | git = "https://github.com/KZen-networks/curv" 30 | tag = "v0.2.0-ed25519" 31 | features=["ec_ed25519"] 32 | 33 | [dependencies.abci] 34 | git="https://github.com/tendermint/rust-abci" 35 | branch="develop" 36 | 37 | [dependencies.tendermint] 38 | version = "0.10.0" 39 | git="https://github.com/amanusk/tendermint-rs" 40 | branch = "develop" 41 | features = ["rpc"] 42 | 43 | [[bin]] 44 | name = "kg-client" 45 | path = "src/bin/kg-client.rs" 46 | 47 | [[bin]] 48 | name = "sign-client" 49 | path = "src/bin/sign-client.rs" 50 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/mmpc-client/src/bin/kg-client.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fs::OpenOptions; 3 | use std::io; 4 | use std::net::SocketAddr; 5 | use std::path::Path; 6 | use std::process; 7 | use std::{thread, time}; 8 | 9 | use clap::{App, Arg, ArgMatches}; 10 | use log::debug; 11 | use serde::Serialize; 12 | 13 | use mmpc_client::eddsa_peer_kg::EddsaPeer; 14 | use mmpc_client::peer::Peer; 15 | use mmpc_client::tendermint_client::SessionClient; 16 | 17 | #[derive(Debug, Serialize)] 18 | struct Record { 19 | index: u32, 20 | millis: u32, 21 | } 22 | 23 | const MAX_RETRY: u32 = 64; 24 | const RETRY_TIMEOUT: u64 = 200; 25 | 26 | fn arg_matches<'a>() -> ArgMatches<'a> { 27 | App::new("relay-server") 28 | .arg( 29 | Arg::with_name("index") 30 | .short("I") 31 | .long("index") 32 | .default_value("1"), 33 | ) 34 | .arg( 35 | Arg::with_name("capacity") 36 | .default_value("2") 37 | .short("C") 38 | .long("capacity"), 39 | ) 40 | .arg( 41 | Arg::with_name("filename") 42 | .default_value("keys") 43 | .long("filename") 44 | .short("F"), 45 | ) 46 | .arg( 47 | Arg::with_name("proxy") 48 | .default_value("127.0.0.1:26657") 49 | .long("proxy"), 50 | ) 51 | .arg( 52 | Arg::with_name("verbose") 53 | .short("v") 54 | .long("verbose") 55 | .multiple(true) 56 | .help("Increases logging verbosity each use for up to 3 times"), 57 | ) 58 | .get_matches() 59 | } 60 | 61 | fn setup_logging(verbosity: u64, index: u32) -> Result<(), fern::InitError> { 62 | let mut base_config = fern::Dispatch::new(); 63 | 64 | base_config = match verbosity { 65 | 0 => base_config 66 | .level(log::LevelFilter::Info) 67 | .level_for("abci::server", log::LevelFilter::Warn), // filter out abci::server 68 | 1 => base_config 69 | .level(log::LevelFilter::Debug) 70 | .level_for("tokio_core", log::LevelFilter::Warn) // filter out tokio 71 | .level_for("tokio_reactor", log::LevelFilter::Warn) 72 | .level_for("hyper", log::LevelFilter::Warn), 73 | _2_or_more => base_config.level(log::LevelFilter::Trace), 74 | }; 75 | 76 | // Separate file config so we can include year, month and day in file logs 77 | let file_config = fern::Dispatch::new() 78 | .format(|out, message, record| { 79 | out.finish(format_args!( 80 | "{}[{}][{}] {} {}", 81 | chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"), 82 | record.target(), 83 | record.level(), 84 | line!(), 85 | message 86 | )) 87 | }) 88 | .chain(fern::log_file(format!("log-kg-{}.log", index))?); 89 | 90 | let stdout_config = fern::Dispatch::new() 91 | .format(|out, message, record| { 92 | // special format for debug messages coming from our own crate. 93 | if record.level() > log::LevelFilter::Info && record.target() == "relay_server" { 94 | out.finish(format_args!( 95 | "---\nDEBUG: {}: {}\n---", 96 | chrono::Local::now().format("%H:%M:%S"), 97 | message 98 | )) 99 | } else { 100 | out.finish(format_args!( 101 | "[{}][{}][{}] {} ", 102 | chrono::Local::now().format("%H:%M:%S"), 103 | record.target(), 104 | record.level(), 105 | message 106 | )) 107 | } 108 | }) 109 | .chain(io::stdout()); 110 | 111 | base_config 112 | .chain(file_config) 113 | .chain(stdout_config) 114 | .apply()?; 115 | 116 | Ok(()) 117 | } 118 | 119 | pub enum MessageProcessResult { 120 | Message, 121 | NoMessage, 122 | Abort, 123 | } 124 | 125 | fn main() { 126 | better_panic::Settings::debug() 127 | .most_recent_first(false) 128 | .lineno_suffix(true) 129 | .install(); 130 | 131 | let matches = arg_matches(); 132 | 133 | let client_index: u32 = matches 134 | .value_of("index") 135 | .unwrap() 136 | .parse() 137 | .expect("Unable to parse index"); 138 | 139 | let capacity: u32 = matches 140 | .value_of("capacity") 141 | .unwrap() 142 | .parse() 143 | .expect("Invalid number of participants"); 144 | 145 | let proxy: String = matches 146 | .value_of("proxy") 147 | .unwrap() 148 | .parse() 149 | .expect("Invalid proxy address"); 150 | 151 | let verbosity: u64 = matches.occurrences_of("verbose"); 152 | 153 | setup_logging(verbosity, client_index).expect("failed to initialize logging."); 154 | 155 | let start_time = time::SystemTime::now(); 156 | let port = 8080 + client_index; 157 | let proxy_addr = format!("tcp://{}", proxy); 158 | let client_addr: SocketAddr = format!("127.0.0.1:{}", port).parse().unwrap(); 159 | debug!("Capacity flag is {}", capacity); 160 | let mut session: SessionClient = SessionClient::new( 161 | client_addr, 162 | &proxy_addr.parse().unwrap(), 163 | client_index, 164 | capacity, 165 | Vec::new(), 166 | ); 167 | // Initially do not request any index, the index is determined by the server 168 | let server_response = session.register(client_index, capacity, -1); 169 | let next_message = session.generate_client_answer(server_response); 170 | debug!("Next message: {:?}", next_message); 171 | // TODO The client/server 172 | let server_response = session.send_message(next_message.unwrap()); 173 | session.store_server_response(&server_response); 174 | 175 | debug!("Server Response: {:?}", server_response); 176 | 177 | for _ in { 1..MAX_RETRY } { 178 | let round = session.state.data_manager.data_holder.current_step(); 179 | debug!("Now on round {}", round); 180 | if session.state.stored_messages.get_number_messages(round) == capacity as usize { 181 | for msg in session 182 | .state 183 | .stored_messages 184 | .get_messages_vector_client_message(round) 185 | { 186 | session.handle_relay_message(msg.clone()); 187 | } 188 | break; 189 | } 190 | let server_response = session.query(); 191 | session.store_server_response(&server_response); 192 | thread::sleep(time::Duration::from_millis(RETRY_TIMEOUT)); 193 | } 194 | let total_time = start_time.elapsed().expect("Weird time"); 195 | println!("{:}", total_time.as_millis()); 196 | 197 | if let Err(err) = write_to_csv(client_index, total_time.as_millis() as u32, capacity) { 198 | println!("error running example: {}", err); 199 | process::exit(1); 200 | } 201 | } 202 | 203 | fn write_to_csv(index: u32, millis: u32, capacity: u32) -> Result<(), Box> { 204 | let filename = format!("exp-kg-{}.csv", capacity); 205 | if Path::new(&filename).exists() { 206 | let file = OpenOptions::new().append(true).open(&filename)?; 207 | 208 | let mut wtr = csv::WriterBuilder::default() 209 | .has_headers(false) 210 | .from_writer(file); 211 | 212 | wtr.serialize(Record { 213 | index: index, 214 | millis: millis, 215 | })?; 216 | wtr.flush()?; 217 | } else { 218 | let file = OpenOptions::new() 219 | .append(true) 220 | .create(true) 221 | .open(&filename)?; 222 | 223 | let mut wtr = csv::WriterBuilder::default() 224 | .has_headers(true) 225 | .from_writer(file); 226 | 227 | wtr.serialize(Record { 228 | index: index, 229 | millis: millis, 230 | })?; 231 | wtr.flush()?; 232 | } 233 | 234 | Ok(()) 235 | } 236 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/mmpc-client/src/bin/sign-client.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fs; 3 | use std::fs::OpenOptions; 4 | use std::io; 5 | use std::net::SocketAddr; 6 | use std::path::Path; 7 | use std::process; 8 | use std::{thread, time}; 9 | 10 | use clap::{App, Arg, ArgMatches}; 11 | use log::debug; 12 | use serde::Serialize; 13 | 14 | use mmpc_client::eddsa_peer_sign::EddsaPeer; 15 | use mmpc_client::peer::Peer; 16 | use mmpc_client::tendermint_client::SessionClient; 17 | 18 | use multi_party_eddsa::protocols::aggsig::{KeyAgg, KeyPair}; 19 | 20 | #[derive(Debug, Serialize)] 21 | struct Record { 22 | index: u32, 23 | millis: u32, 24 | } 25 | 26 | const MAX_RETRY: u32 = 512; 27 | const RETRY_TIMEOUT: u64 = 200; 28 | 29 | fn arg_matches<'a>() -> ArgMatches<'a> { 30 | App::new("relay-server") 31 | .arg( 32 | Arg::with_name("index") 33 | .short("I") 34 | .long("index") 35 | .default_value("1"), 36 | ) 37 | .arg( 38 | Arg::with_name("capacity") 39 | .default_value("2") 40 | .short("C") 41 | .long("capacity"), 42 | ) 43 | .arg( 44 | Arg::with_name("filename") 45 | .default_value("keys") 46 | .long("filename") 47 | .short("F"), 48 | ) 49 | .arg( 50 | Arg::with_name("message") 51 | .default_value("message") 52 | .long("message") 53 | .short("M"), 54 | ) 55 | .arg( 56 | Arg::with_name("proxy") 57 | .default_value("127.0.0.1:26657") 58 | .long("proxy"), 59 | ) 60 | .get_matches() 61 | } 62 | 63 | fn setup_logging(verbosity: u64, index: u32) -> Result<(), fern::InitError> { 64 | let mut base_config = fern::Dispatch::new(); 65 | 66 | base_config = match verbosity { 67 | 0 => base_config 68 | .level(log::LevelFilter::Info) 69 | .level_for("abci::server", log::LevelFilter::Warn), // filter out abci::server 70 | 1 => base_config 71 | .level(log::LevelFilter::Debug) 72 | .level_for("tokio_core", log::LevelFilter::Warn) // filter out tokio 73 | .level_for("tokio_reactor", log::LevelFilter::Warn) 74 | .level_for("hyper", log::LevelFilter::Warn), 75 | _2_or_more => base_config.level(log::LevelFilter::Trace), 76 | }; 77 | 78 | // Separate file config so we can include year, month and day in file logs 79 | let file_config = fern::Dispatch::new() 80 | .format(|out, message, record| { 81 | out.finish(format_args!( 82 | "{}[{}][{}] {} {}", 83 | chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"), 84 | record.target(), 85 | record.level(), 86 | line!(), 87 | message 88 | )) 89 | }) 90 | .chain(fern::log_file(format!("log-sign-{}.log", index))?); 91 | 92 | let stdout_config = fern::Dispatch::new() 93 | .format(|out, message, record| { 94 | // special format for debug messages coming from our own crate. 95 | if record.level() > log::LevelFilter::Info && record.target() == "mmpc_client" { 96 | out.finish(format_args!( 97 | "---\nDEBUG: {}: {}\n---", 98 | chrono::Local::now().format("%H:%M:%S"), 99 | message 100 | )) 101 | } else { 102 | out.finish(format_args!( 103 | "[{}][{}][{}] {} ", 104 | chrono::Local::now().format("%H:%M:%S"), 105 | record.target(), 106 | record.level(), 107 | message 108 | )) 109 | } 110 | }) 111 | .chain(io::stdout()); 112 | 113 | base_config 114 | .chain(file_config) 115 | .chain(stdout_config) 116 | .apply()?; 117 | 118 | Ok(()) 119 | } 120 | 121 | fn main() { 122 | better_panic::Settings::debug() 123 | .most_recent_first(false) 124 | .lineno_suffix(true) 125 | .install(); 126 | 127 | let matches = arg_matches(); 128 | 129 | let client_index: u32 = matches 130 | .value_of("index") 131 | .unwrap() 132 | .parse() 133 | .expect("Unable to parse index"); 134 | 135 | let capacity: u32 = matches 136 | .value_of("capacity") 137 | .unwrap() 138 | .parse() 139 | .expect("Invalid number of participants"); 140 | 141 | let message: String = matches 142 | .value_of("message") 143 | .unwrap() 144 | .parse() 145 | .expect("Invalid message to sign"); 146 | 147 | let proxy: String = matches 148 | .value_of("proxy") 149 | .unwrap() 150 | .parse() 151 | .expect("Invalid proxy address"); 152 | 153 | let verbosity: u64 = matches.occurrences_of("verbose"); 154 | setup_logging(verbosity, client_index).expect("failed to initialize logging."); 155 | 156 | let message_to_sign = match hex::decode(message.to_owned()) { 157 | Ok(x) => x, 158 | Err(_) => message.as_bytes().to_vec(), 159 | }; 160 | 161 | let data = fs::read_to_string(format!("keys{}", client_index)) 162 | .expect("Unable to load keys, did you run keygen first? "); 163 | let (_, _, kg_index): (KeyPair, KeyAgg, i32) = serde_json::from_str(&data).unwrap(); 164 | 165 | // Port and ip address are used as a unique indetifier to the server 166 | // This should be replaced with PKi down the road 167 | let start_time = time::SystemTime::now(); 168 | let port = 8080 + client_index; 169 | let proxy_addr = format!("tcp://{}", proxy); 170 | let client_addr: SocketAddr = format!("127.0.0.1:{}", port).parse().unwrap(); 171 | let mut session: SessionClient = SessionClient::new( 172 | client_addr, 173 | &proxy_addr.parse().unwrap(), 174 | client_index, 175 | capacity, 176 | message_to_sign, 177 | ); 178 | let server_response = session.register(client_index, capacity, kg_index); 179 | let mut next_message = session.generate_client_answer(server_response); 180 | debug!("Next message: {:?}", next_message); 181 | // TODO The client/server response could be an error 182 | let mut server_response = session.send_message(next_message.clone().unwrap()); 183 | session.store_server_response(&server_response); 184 | // Number of rounds in signing 185 | let rounds = 4; 186 | 'outer: for _ in 0..rounds { 187 | 'inner: for _ in { 1..MAX_RETRY } { 188 | let round = session.state.data_manager.data_holder.current_step(); 189 | if session.state.stored_messages.get_number_messages(round) == capacity as usize { 190 | for msg in session 191 | .state 192 | .stored_messages 193 | .get_messages_vector_client_message(round) 194 | { 195 | next_message = session.handle_relay_message(msg.clone()); 196 | } 197 | // Do not send response on last round 198 | if round != rounds - 1 { 199 | server_response = session.send_message(next_message.clone().unwrap()); 200 | session.store_server_response(&server_response); 201 | } 202 | break 'inner; 203 | } else { 204 | let server_response = session.query(); 205 | // debug!("Server response {:?}", server_response); 206 | // debug!("Server response len {}", server_response.keys().len()); 207 | session.store_server_response(&server_response); 208 | thread::sleep(time::Duration::from_millis(RETRY_TIMEOUT)); 209 | // debug!("All stored messages {:?}", session.state.stored_messages); 210 | } 211 | } 212 | } 213 | 214 | let total_time = start_time.elapsed().expect("Weird time"); 215 | println!("{:}", total_time.as_millis()); 216 | 217 | if let Err(err) = write_to_csv(client_index, total_time.as_millis() as u32, capacity) { 218 | println!("error running example: {}", err); 219 | process::exit(1); 220 | } 221 | } 222 | 223 | fn write_to_csv(index: u32, millis: u32, capacity: u32) -> Result<(), Box> { 224 | let filename = format!("exp-sign-{}.csv", capacity); 225 | if Path::new(&filename).exists() { 226 | let file = OpenOptions::new().append(true).open(&filename)?; 227 | 228 | let mut wtr = csv::WriterBuilder::default() 229 | .has_headers(false) 230 | .from_writer(file); 231 | 232 | wtr.serialize(Record { 233 | index: index, 234 | millis: millis, 235 | })?; 236 | wtr.flush()?; 237 | } else { 238 | let file = OpenOptions::new() 239 | .append(true) 240 | .create(true) 241 | .open(&filename)?; 242 | 243 | let mut wtr = csv::WriterBuilder::default() 244 | .has_headers(true) 245 | .from_writer(file); 246 | 247 | wtr.serialize(Record { 248 | index: index, 249 | millis: millis, 250 | })?; 251 | wtr.flush()?; 252 | } 253 | 254 | Ok(()) 255 | } 256 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/mmpc-client/src/eddsa_peer_kg.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::fs; 3 | 4 | use curv::elliptic::curves::ed25519::*; 5 | use log::{debug, info}; 6 | use multi_party_eddsa::protocols::aggsig::{EphemeralKey, KeyAgg, KeyPair}; 7 | 8 | use crate::peer::Peer; 9 | use mmpc_server_common::common::*; 10 | use mmpc_server_common::{MessagePayload, PeerIdentifier}; 11 | 12 | #[allow(non_snake_case)] 13 | pub struct EddsaPeer { 14 | // this peers identifier in this session 15 | pub peer_id: PeerIdentifier, 16 | // # of participants 17 | pub capacity: u32, 18 | 19 | pub current_step: u32, 20 | // is peer done with all calculations 21 | pub is_done: bool, 22 | 23 | // eddsa data 24 | pub client_key: KeyPair, 25 | pub pks: HashMap, 26 | pub commitments: HashMap, 27 | pub r_s: HashMap, 28 | pub sigs: HashMap, 29 | pub ephemeral_key: Option, 30 | 31 | pub agg_key: Option, 32 | pub R_tot: Option, 33 | 34 | // indicators for which of this peers messages were accepted 35 | pub pk_accepted: bool, 36 | pub commitment_accepted: bool, 37 | pub r_accepted: bool, 38 | pub sig_accepted: bool, 39 | 40 | // messages this peer generates 41 | pub pk_msg: Option, 42 | pub commitment_msg: Option, 43 | pub r_msg: Option, 44 | pub sig_msg: Option, 45 | } 46 | 47 | impl Peer for EddsaPeer { 48 | fn new(capacity: u32, _message: Vec, _index: u32) -> EddsaPeer { 49 | debug!("Capacity is set to {}", capacity); 50 | EddsaPeer { 51 | client_key: KeyPair::create(), 52 | pks: HashMap::new(), 53 | commitments: HashMap::new(), 54 | r_s: HashMap::new(), 55 | sigs: HashMap::new(), 56 | capacity, 57 | peer_id: 0, 58 | agg_key: None, 59 | current_step: 0, 60 | R_tot: None, 61 | ephemeral_key: None, 62 | pk_accepted: false, 63 | commitment_accepted: false, 64 | r_accepted: false, 65 | sig_accepted: false, 66 | is_done: false, 67 | 68 | pk_msg: None, 69 | commitment_msg: None, 70 | r_msg: None, 71 | sig_msg: None, 72 | } 73 | } 74 | 75 | fn set_peer_id(&mut self, peer_id: PeerIdentifier) { 76 | self.peer_id = peer_id; 77 | } 78 | 79 | fn zero_step(&mut self, peer_id: PeerIdentifier) -> Option { 80 | self.peer_id = peer_id; 81 | let pk = self.client_key.public_key.clone(); 82 | 83 | let pk_s = serde_json::to_string(&pk).expect("Failed in serialization"); 84 | 85 | self.pk_msg = Some(generate_pk_message_payload(&pk_s)); 86 | return self.pk_msg.clone(); 87 | } 88 | 89 | fn current_step(&self) -> u32 { 90 | self.current_step 91 | } 92 | 93 | fn capacity(&self) -> u32 { 94 | self.capacity 95 | } 96 | 97 | fn peer_id(&self) -> PeerIdentifier { 98 | self.peer_id 99 | } 100 | 101 | fn do_step(&mut self) { 102 | debug!("Current step is: {:}", self.current_step); 103 | if self.is_step_done() { 104 | // do the next step 105 | debug!("step {:} done!", self.current_step); 106 | self.current_step += 1; 107 | match self.current_step { 108 | 1 => { 109 | info!("----------\nDone.\n----------"); 110 | self.is_done = true; 111 | } 112 | _ => panic!("Unsupported step"), 113 | } 114 | } else { 115 | debug!("step not done"); 116 | } 117 | } 118 | 119 | fn update_data(&mut self, from: PeerIdentifier, payload: MessagePayload) { 120 | // update data according to step 121 | debug!("Current step {}", self.current_step); 122 | match self.current_step { 123 | 0 => self.update_data_step_0(from, payload), 124 | 125 | _ => panic!("Unsupported step"), 126 | } 127 | } 128 | /// Does the final calculation of the protocol 129 | /// in this case: 130 | /// collection all signatures 131 | /// and verifying the message 132 | fn finalize(&mut self) -> Result<(), &'static str> { 133 | let key = &self.client_key.clone(); 134 | let apk = &self.aggregate_pks(); 135 | let index = &self.peer_id; 136 | 137 | let keygen_json = serde_json::to_string(&(key, apk, index)).unwrap(); 138 | 139 | let res = fs::write(format!("keys{}", self.peer_id), keygen_json); 140 | match res { 141 | Ok(_) => Ok(()), 142 | Err(_) => Err("Failed to verify"), 143 | } 144 | } 145 | /// check that the protocol is done 146 | /// and that this peer can finalize its calculations 147 | fn is_done(&mut self) -> bool { 148 | self.is_done_step_0() 149 | } 150 | 151 | /// get the next item the peer needs to send 152 | /// depending on the current step and the last message 153 | /// of the peer that was accepted by the server 154 | fn get_next_item(&mut self) -> Option { 155 | if self.current_step == 0 || !self.pk_accepted { 156 | debug!("next item is pk: {:?}", self.pk_msg); 157 | return self.pk_msg.clone(); 158 | } 159 | None 160 | } 161 | } 162 | 163 | impl EddsaPeer { 164 | fn is_step_done(&mut self) -> bool { 165 | match self.current_step { 166 | 0 => return self.is_done_step_0(), 167 | _ => panic!("Unsupported step"), 168 | } 169 | } 170 | pub fn is_done_step_0(&mut self) -> bool { 171 | if self.pks.len() == self.capacity() as usize { 172 | self.finalize().expect("Finalized falied"); 173 | return true; 174 | } 175 | false 176 | } 177 | } 178 | 179 | impl EddsaPeer { 180 | pub fn resolve_payload_type(message: &MessagePayload) -> MessagePayloadType { 181 | let msg_payload = message.clone(); 182 | 183 | let split_msg: Vec<&str> = msg_payload.split(RELAY_MESSAGE_DELIMITER).collect(); 184 | let msg_prefix = split_msg[0]; 185 | let msg_payload = String::from(split_msg[1].clone()); 186 | match msg_prefix { 187 | pk_prefix if pk_prefix == String::from(PK_MESSAGE_PREFIX) => { 188 | return MessagePayloadType::PublicKey(msg_payload); 189 | } 190 | _ => panic!("Unknown relay message prefix"), 191 | } 192 | } 193 | } 194 | 195 | impl EddsaPeer { 196 | /// data updaters for each step 197 | pub fn update_data_step_0(&mut self, from: PeerIdentifier, payload: MessagePayload) { 198 | let payload_type = EddsaPeer::resolve_payload_type(&payload); 199 | match payload_type { 200 | MessagePayloadType::PublicKey(pk) => { 201 | let peer_id = self.peer_id; 202 | if from == peer_id { 203 | self.pk_accepted = true; 204 | } 205 | let s_slice: &str = &pk[..]; // take a full slice of the string 206 | let _pk = serde_json::from_str(s_slice); 207 | info!("-------Got peer # {:} pk! {:?}", from, pk); 208 | match _pk { 209 | Ok(_pk) => self.add_pk(from, _pk), 210 | Err(_) => panic!("Could not serialize public key"), 211 | } 212 | } 213 | } 214 | } 215 | } 216 | 217 | impl EddsaPeer { 218 | /// inner calculations & data manipulations 219 | fn add_pk(&mut self, peer_id: PeerIdentifier, pk: Ed25519Point) { 220 | self.pks.insert(peer_id, pk); 221 | } 222 | fn aggregate_pks(&mut self) -> KeyAgg { 223 | debug!("aggregating pks"); 224 | let _cap = self.capacity() as usize; 225 | let mut pks = Vec::with_capacity(self.capacity() as usize); 226 | for index in 0..self.capacity() { 227 | let peer = index + 1; 228 | let pk = self.pks.get_mut(&peer).unwrap(); 229 | pks.push(pk.clone()); 230 | } 231 | debug!("# of public keys : {:?}", pks.len()); 232 | let peer_id = self.peer_id; 233 | let index = (peer_id - 1) as usize; 234 | let agg_key = KeyPair::key_aggregation_n(&pks, &index); 235 | return agg_key; 236 | } 237 | } 238 | 239 | #[derive(Debug)] 240 | pub enum MessagePayloadType { 241 | /// Types of expected relay messages 242 | /// for step 0 we expect PUBLIC_KEY_MESSAGE 243 | PublicKey(String), 244 | } 245 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/mmpc-client/src/eddsa_peer_sign.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::fs; 3 | 4 | use curv::arithmetic::traits::Converter; 5 | use curv::elliptic::curves::ed25519::*; 6 | use curv::elliptic::curves::traits::ECPoint; 7 | use curv::elliptic::curves::traits::ECScalar; 8 | use curv::{BigInt, FE, GE}; 9 | use log::{debug, info}; 10 | use multi_party_eddsa::protocols::aggsig::{ 11 | test_com, verify, EphemeralKey, KeyAgg, KeyPair, SignFirstMsg, SignSecondMsg, Signature, 12 | }; 13 | 14 | use crate::peer::Peer; 15 | use mmpc_server_common::common::*; 16 | use mmpc_server_common::{MessagePayload, PeerIdentifier}; 17 | 18 | #[derive(Debug)] 19 | pub enum MessagePayloadType { 20 | /// Types of expected relay messages 21 | /// for step 0 we expect PUBLIC_KEY_MESSAGE 22 | /// for step 1 we expect Commitment 23 | /// for step 2 we expect RMessage 24 | /// for step 3 we expect Signature 25 | PublicKey(String), 26 | Commitment(String), 27 | RMessage(String), 28 | Signature(String), 29 | } 30 | 31 | #[allow(non_snake_case)] 32 | pub struct EddsaPeer { 33 | // this peers identifier in this session 34 | pub peer_id: PeerIdentifier, 35 | // # of participants 36 | pub capacity: u32, 37 | 38 | pub current_step: u32, 39 | // is peer done with all calculations 40 | pub is_done: bool, 41 | 42 | // eddsa data 43 | pub client_key: KeyPair, 44 | pub pks: HashMap, 45 | pub commitments: HashMap, 46 | pub r_s: HashMap, 47 | pub sigs: HashMap, 48 | pub ephemeral_key: Option, 49 | // message to sign 50 | pub message: Vec, 51 | 52 | pub agg_key: Option, 53 | pub kg_index: u32, 54 | pub R_tot: Option, 55 | 56 | // indicators for which of this peers messages were accepted 57 | pub pk_accepted: bool, 58 | pub commitment_accepted: bool, 59 | pub r_accepted: bool, 60 | pub sig_accepted: bool, 61 | 62 | // messages this peer generates 63 | pub pk_msg: Option, 64 | pub commitment_msg: Option, 65 | pub r_msg: Option, 66 | pub sig_msg: Option, 67 | } 68 | 69 | impl EddsaPeer { 70 | /// inner calculations & data manipulations 71 | fn add_pk(&mut self, peer_id: PeerIdentifier, pk: Ed25519Point) { 72 | self.pks.insert(peer_id, pk); 73 | } 74 | fn add_commitment(&mut self, peer_id: PeerIdentifier, commitment: String) { 75 | self.commitments.insert(peer_id, commitment); 76 | } 77 | fn add_r(&mut self, peer_id: PeerIdentifier, r: String) { 78 | //let v = (r,blind_factor); 79 | self.r_s.insert(peer_id, r); 80 | } 81 | fn add_sig(&mut self, peer_id: PeerIdentifier, sig: String) { 82 | self.sigs.insert(peer_id, sig); 83 | } 84 | fn compute_r_tot(&mut self) -> GE { 85 | #[allow(non_snake_case)] 86 | let mut Ri: Vec = Vec::new(); 87 | for (_peer_id, r) in &self.r_s { 88 | let r_slice: &str = &r[..]; 89 | let r: SignSecondMsg = 90 | serde_json::from_str(r_slice).unwrap_or_else(|_| panic!("Serialization error")); 91 | Ri.push(r.R.clone()); 92 | } 93 | let r_tot = Signature::get_R_tot(Ri); 94 | return r_tot; 95 | } 96 | fn aggregate_pks(&mut self) -> KeyAgg { 97 | debug!("aggregating pks"); 98 | let _cap = self.capacity as usize; 99 | let mut pks = Vec::with_capacity(self.capacity as usize); 100 | for index in 0..self.capacity { 101 | let peer = index + 1; 102 | let pk = self.pks.get_mut(&peer).unwrap(); 103 | pks.push(pk.clone()); 104 | } 105 | debug!("# of public keys : {:?}", pks.len()); 106 | let peer_id = self.peer_id; 107 | let index = (peer_id - 1) as usize; 108 | debug!("Public keys {:?}", &pks); 109 | debug!("KG index:{}, SIG index:{}", self.kg_index, peer_id); 110 | // TODO: sort the pks according to key-gen indexes when applying 111 | KeyPair::key_aggregation_n(&pks, &index) 112 | } 113 | 114 | fn validate_commitments(&mut self) -> bool { 115 | // iterate over all peer Rs 116 | debug!("----------\nvalidating commitments\n----------"); 117 | let eight: FE = ECScalar::from(&BigInt::from(8)); 118 | let eight_inv = eight.invert(); 119 | let r_s = &self.r_s; 120 | for (peer_id, r) in r_s { 121 | debug!("peer: {:}", peer_id); 122 | debug!("r: {:}", r); 123 | // convert the json_string to a construct 124 | let _r: SignSecondMsg = serde_json::from_str(r).unwrap(); 125 | 126 | // get the corresponding commitment 127 | let k = peer_id.clone(); 128 | let cmtmnt = self 129 | .commitments 130 | .get(&k) 131 | .expect("peer didn't send commitment"); 132 | debug!("commitment : {:?}", cmtmnt); 133 | let commitment: SignFirstMsg = serde_json::from_str(cmtmnt).unwrap(); 134 | // if we couldn't validate the commitment - failure 135 | if !test_com( 136 | &(_r.R * eight_inv), 137 | &_r.blind_factor, 138 | &commitment.commitment, 139 | ) { 140 | return false; 141 | } 142 | } 143 | debug!("----------\ncommitments valid\n----------"); 144 | true 145 | } 146 | } 147 | 148 | impl EddsaPeer { 149 | /// data updaters for each step 150 | pub fn update_data_step_0(&mut self, from: PeerIdentifier, payload: MessagePayload) { 151 | let payload_type = EddsaPeer::resolve_payload_type(&payload); 152 | let eight: FE = ECScalar::from(&BigInt::from(8)); 153 | let eight_inv = eight.invert(); 154 | match payload_type { 155 | MessagePayloadType::PublicKey(pk) => { 156 | let peer_id = self.peer_id; 157 | if from == peer_id { 158 | self.pk_accepted = true; 159 | } 160 | let s_slice: &str = &pk[..]; // take a full slice of the string 161 | let pk: GE = serde_json::from_str(&s_slice) 162 | .unwrap_or_else(|_| panic!("Failed to deserialize R")); 163 | info!("-------Got peer # {:} pk! {:?}", from, pk * &eight_inv); 164 | self.add_pk(from, pk * &eight_inv); 165 | } 166 | _ => panic!("expected public key message"), 167 | } 168 | } 169 | 170 | pub fn update_data_step_1(&mut self, from: PeerIdentifier, payload: MessagePayload) { 171 | let payload_type = EddsaPeer::resolve_payload_type(&payload); 172 | match payload_type { 173 | MessagePayloadType::Commitment(t) => { 174 | info!("-------Got peer # {:} commitment! {:?}", from, t); 175 | let peer_id = self.peer_id; 176 | if from == peer_id { 177 | self.commitment_accepted = true; 178 | } 179 | self.add_commitment(from, t); 180 | } 181 | _ => {} //panic!("expected commitment message") 182 | } 183 | } 184 | 185 | pub fn update_data_step_2(&mut self, from: PeerIdentifier, payload: MessagePayload) { 186 | let payload_type = EddsaPeer::resolve_payload_type(&payload); 187 | match payload_type { 188 | MessagePayloadType::RMessage(r) => { 189 | info!("-------Got peer # {:} R message!", from); 190 | let peer_id = self.peer_id; 191 | if from == peer_id { 192 | self.r_accepted = true; 193 | } 194 | self.add_r(from, r); 195 | } 196 | _ => {} //panic!("expected R message") 197 | } 198 | } 199 | 200 | pub fn update_data_step_3(&mut self, from: PeerIdentifier, payload: MessagePayload) { 201 | debug!("updating data step 3"); 202 | let payload_type = EddsaPeer::resolve_payload_type(&payload); 203 | match payload_type { 204 | MessagePayloadType::Signature(s) => { 205 | debug!("-------Got peer # {:} Signature", from); 206 | let peer_id = self.peer_id; 207 | if from == peer_id { 208 | self.sig_accepted = true; 209 | } 210 | self.add_sig(from, s); 211 | } 212 | _ => {} //panic!("expected signature message") 213 | } 214 | } 215 | } 216 | 217 | impl EddsaPeer { 218 | fn is_step_done(&mut self) -> bool { 219 | match self.current_step { 220 | 0 => return self.is_done_step_0(), 221 | 1 => return self.is_done_step_1(), 222 | 2 => return self.is_done_step_2(), 223 | 3 => return self.is_done_step_3(), 224 | _ => panic!("Unsupported step"), 225 | } 226 | } 227 | pub fn is_done_step_0(&self) -> bool { 228 | self.pks.len() == self.capacity as usize 229 | } 230 | pub fn is_done_step_1(&self) -> bool { 231 | self.commitments.len() == self.capacity as usize 232 | } 233 | pub fn is_done_step_2(&self) -> bool { 234 | self.r_s.len() == self.capacity as usize 235 | } 236 | pub fn is_done_step_3(&mut self) -> bool { 237 | debug!("Checking if last step is done"); 238 | 239 | if self.sigs.len() == self.capacity as usize { 240 | self.finalize().unwrap(); 241 | return true; 242 | } 243 | false 244 | } 245 | } 246 | 247 | impl EddsaPeer { 248 | /// steps - in each step the client does a calculation on its 249 | /// data, and updates the data holder with the new data 250 | 251 | /// step 1 - calculate key and commitment 252 | pub fn step_1(&mut self) { 253 | // each peer computes its commitment to the ephemeral key 254 | // (this implicitly means each party also calculates ephemeral key 255 | // on this step) 256 | // round 1: send commitments to ephemeral public keys 257 | //let mut k = &self.client_key; 258 | let (ephemeral_key, sign_first_message, sign_second_message) = 259 | Signature::create_ephemeral_key_and_commit(&self.client_key, &self.message[..]); 260 | 261 | self.ephemeral_key = Some(ephemeral_key); 262 | // save the commitment 263 | let _peer_id = self.peer_id; 264 | match serde_json::to_string(&sign_first_message) { 265 | Ok(json_string) => { 266 | // self.add_commitment(peer_id, json_string.clone()); 267 | let r = serde_json::to_string(&sign_second_message).expect("couldn't create R"); 268 | self.commitment_msg = Some(generate_commitment_message_payload(&json_string)); 269 | self.r_msg = Some(generate_R_message_payload(&r)); 270 | } 271 | Err(_) => panic!("Couldn't serialize commitment"), 272 | } 273 | } 274 | 275 | /// step 2 - return the clients R. No extra calculations 276 | pub fn step_2(&mut self) { 277 | debug!("Step 2 - no calculations required. Relevant values should be ready"); 278 | } 279 | /// step 3 - after validating all commitments: 280 | /// 1. compute APK 281 | /// 2. compute R' = sum(Ri) 282 | /// 3. sign message 283 | pub fn step_3(&mut self) { 284 | if !self.validate_commitments() { 285 | // commitments sent by others are not valid. exit 286 | panic!("Commitments not valid!") 287 | } 288 | let agg_key = self.aggregate_pks(); 289 | debug!("computed agg_key"); 290 | let r_tot = self.compute_r_tot(); 291 | debug!("computed r_tot"); 292 | // let eph_key = self.ephemeral_key.clone(); 293 | match self.ephemeral_key { 294 | Some(ref eph_key) => { 295 | let k = Signature::k(&r_tot, &agg_key.apk, &self.message[..]); 296 | let peer_id = self.peer_id; 297 | let r = self 298 | .r_s 299 | .get(&peer_id) 300 | .unwrap_or_else(|| panic!("Client has No R ")) 301 | .clone(); 302 | let _r: SignSecondMsg = 303 | serde_json::from_str(&r).unwrap_or_else(|_| panic!("Failed to deserialize R")); 304 | let key = &self.client_key; 305 | // sign 306 | let s = Signature::partial_sign(&eph_key.r, key, &k, &agg_key.hash, &r_tot); 307 | let sig_string = serde_json::to_string(&s).expect("failed to serialize signature"); 308 | self.sig_msg = Some(generate_signature_message_payload(&sig_string)); 309 | } 310 | None => {} 311 | } 312 | } 313 | } 314 | 315 | impl EddsaPeer { 316 | pub fn resolve_payload_type(message: &MessagePayload) -> MessagePayloadType { 317 | let msg_payload = message.clone(); 318 | 319 | let split_msg: Vec<&str> = msg_payload.split(RELAY_MESSAGE_DELIMITER).collect(); 320 | let msg_prefix = split_msg[0]; 321 | let msg_payload = String::from(split_msg[1].clone()); 322 | match msg_prefix { 323 | pk_prefix if pk_prefix == String::from(PK_MESSAGE_PREFIX) => { 324 | return MessagePayloadType::PublicKey(msg_payload); 325 | } 326 | cmtmnt if cmtmnt == String::from(COMMITMENT_MESSAGE_PREFIX) => { 327 | return MessagePayloadType::Commitment(msg_payload); 328 | } 329 | r if r == String::from(R_KEY_MESSAGE_PREFIX) => { 330 | return MessagePayloadType::RMessage(msg_payload); 331 | } 332 | sig if sig == String::from(SIGNATURE_MESSAGE_PREFIX) => { 333 | return MessagePayloadType::Signature(msg_payload); 334 | } 335 | _ => panic!("Unknown relay message prefix"), 336 | } 337 | } 338 | } 339 | 340 | impl Peer for EddsaPeer { 341 | fn new(capacity: u32, _message: Vec, index: u32) -> EddsaPeer { 342 | debug!("Index is {:?}", index); 343 | let data = fs::read_to_string(format!("keys{}", index)) 344 | .expect("Unable to load keys, did you run keygen first? "); 345 | let (key, _apk, kg_index): (KeyPair, KeyAgg, u32) = serde_json::from_str(&data).unwrap(); 346 | EddsaPeer { 347 | client_key: { key }, 348 | pks: HashMap::new(), 349 | commitments: HashMap::new(), 350 | r_s: HashMap::new(), 351 | sigs: HashMap::new(), 352 | capacity, 353 | message: _message, 354 | peer_id: 0, 355 | agg_key: None, 356 | kg_index, 357 | current_step: 0, 358 | R_tot: None, 359 | ephemeral_key: None, 360 | pk_accepted: false, 361 | commitment_accepted: false, 362 | r_accepted: false, 363 | sig_accepted: false, 364 | is_done: false, 365 | 366 | pk_msg: None, 367 | commitment_msg: None, 368 | r_msg: None, 369 | sig_msg: None, 370 | } 371 | } 372 | 373 | fn set_peer_id(&mut self, peer_id: PeerIdentifier) { 374 | self.peer_id = peer_id; 375 | } 376 | 377 | fn zero_step(&mut self, peer_id: PeerIdentifier) -> Option { 378 | self.peer_id = peer_id; 379 | let pk = self.client_key.public_key.clone(); 380 | 381 | let pk_s = serde_json::to_string(&pk).expect("Failed in serialization"); 382 | 383 | self.pk_msg = Some(generate_pk_message_payload(&pk_s)); 384 | return self.pk_msg.clone(); 385 | } 386 | 387 | fn current_step(&self) -> u32 { 388 | self.current_step 389 | } 390 | 391 | fn capacity(&self) -> u32 { 392 | self.capacity 393 | } 394 | 395 | fn peer_id(&self) -> PeerIdentifier { 396 | self.peer_id 397 | } 398 | 399 | fn do_step(&mut self) { 400 | info!("Current step is: {:}", self.current_step); 401 | if self.is_step_done() { 402 | // do the next step 403 | info!("step {:} done!", self.current_step); 404 | self.current_step += 1; 405 | match self.current_step { 406 | 1 => self.step_1(), 407 | 2 => self.step_2(), 408 | 3 => self.step_3(), 409 | 4 => { 410 | info!("----------\nDone.\n----------"); 411 | self.is_done = true; 412 | } 413 | _ => panic!("Unsupported step"), 414 | } 415 | } else { 416 | info!("step not done"); 417 | } 418 | } 419 | 420 | fn update_data(&mut self, from: PeerIdentifier, payload: MessagePayload) { 421 | // update data according to step 422 | match self.current_step { 423 | 0 => self.update_data_step_0(from, payload), 424 | 1 => self.update_data_step_1(from, payload), 425 | 2 => self.update_data_step_2(from, payload), 426 | 3 => self.update_data_step_3(from, payload), 427 | _ => panic!("Unsupported step"), 428 | } 429 | } 430 | /// Does the final calculation of the protocol 431 | /// in this case: 432 | /// collection all signatures 433 | /// and verifying the message 434 | #[allow(non_snake_case)] 435 | fn finalize(&mut self) -> Result<(), &'static str> { 436 | let mut s: Vec = Vec::new(); 437 | let eight: FE = ECScalar::from(&BigInt::from(8)); 438 | let eight_inv = eight.invert(); 439 | for sig in self.sigs.values() { 440 | let signature: Signature = 441 | serde_json::from_str(&sig).expect("Could not serialize signature!"); 442 | s.push(Signature { 443 | R: signature.R * eight_inv, 444 | s: signature.s * &eight, 445 | }) 446 | } 447 | let signature = Signature::add_signature_parts(s); 448 | // verify message with signature 449 | let apk = self.aggregate_pks(); 450 | 451 | let data = fs::read_to_string(format!("keys{}", self.peer_id)) 452 | .expect("Unable to load keys, did you run keygen first? "); 453 | let (_key, orig_apk, _kg_index): (KeyPair, KeyAgg, u32) = 454 | serde_json::from_str(&data).unwrap(); 455 | 456 | let eight: FE = ECScalar::from(&BigInt::from(8)); 457 | let eight_inv = eight.invert(); 458 | 459 | let orig_apk = orig_apk.apk * &eight_inv; 460 | 461 | debug!("Aggregated pk {:?}", apk); 462 | debug!("Orig pk {:?}", orig_apk); 463 | // Original apk should be equal to the apk created during signing 464 | assert_eq!(orig_apk, apk.apk); 465 | //assert_eq!(apk, apk.apk); 466 | // Verify signature against the original! pubkey 467 | match verify(&signature, &self.message[..], &orig_apk) { 468 | Ok(_) => { 469 | let mut R_vec = signature.R.pk_to_key_slice().to_vec(); 470 | let mut s_vec = BigInt::to_vec(&signature.s.to_big_int()); 471 | s_vec.reverse(); 472 | R_vec.extend_from_slice(&s_vec[..]); 473 | 474 | fs::write( 475 | format!("signature{}", self.peer_id), 476 | BigInt::from(&R_vec[..]).to_str_radix(16), 477 | ) 478 | .expect("Unable to save !"); 479 | Ok(()) 480 | } 481 | Err(_) => Err("Failed to verify"), 482 | } 483 | } 484 | /// check that the protocol is done 485 | /// and that this peer can finalize its calculations 486 | fn is_done(&mut self) -> bool { 487 | self.is_done_step_3() 488 | } 489 | 490 | /// get the next item the peer needs to send 491 | /// depending on the current step and the last message 492 | /// of the peer that was accepted by the server 493 | fn get_next_item(&mut self) -> Option { 494 | if self.current_step == 0 || !self.pk_accepted { 495 | info!("next item is pk: {:?}", self.pk_msg); 496 | return self.pk_msg.clone(); 497 | } 498 | if self.current_step == 1 || !self.commitment_accepted { 499 | info!("next item is commitment: {:?}", self.commitment_msg); 500 | return self.commitment_msg.clone(); 501 | } 502 | if self.current_step == 2 || !self.r_accepted { 503 | info!("next item is r: {:?}", self.r_msg); 504 | return self.r_msg.clone(); 505 | } 506 | if self.current_step == 3 || !self.sig_accepted { 507 | info!("next item is Signature: {:?}", self.sig_msg); 508 | return self.sig_msg.clone(); 509 | } 510 | None 511 | } 512 | } 513 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/mmpc-client/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod eddsa_peer_kg; 2 | pub mod eddsa_peer_sign; 3 | pub mod peer; 4 | pub mod tendermint_client; 5 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/mmpc-client/src/peer.rs: -------------------------------------------------------------------------------- 1 | use mmpc_server_common::{MessagePayload, PeerIdentifier}; 2 | 3 | pub const MAX_CLIENTS: usize = 12; 4 | 5 | pub trait Peer { 6 | fn new(capacity: u32, message: Vec, index: u32) -> Self; 7 | fn zero_step(&mut self, peer_id: PeerIdentifier) -> Option; 8 | fn current_step(&self) -> u32; 9 | fn capacity(&self) -> u32; 10 | fn peer_id(&self) -> PeerIdentifier; 11 | fn set_peer_id(&mut self, peer_id: PeerIdentifier); 12 | fn do_step(&mut self); 13 | fn update_data(&mut self, from: PeerIdentifier, payload: MessagePayload); 14 | fn get_next_item(&mut self) -> Option; 15 | fn finalize(&mut self) -> Result<(), &'static str>; 16 | fn is_done(&mut self) -> bool; 17 | } 18 | 19 | pub struct ProtocolDataManager { 20 | pub data_holder: T, // will be filled when initializing, and on each new step 21 | pub client_data: Option, // new data calculated by this peer at the beginning of a step (that needs to be sent to other peers) 22 | pub new_client_data: bool, 23 | } 24 | 25 | impl ProtocolDataManager { 26 | pub fn new(capacity: u32, message: Vec, index: u32) -> ProtocolDataManager 27 | where 28 | T: Peer, 29 | { 30 | ProtocolDataManager { 31 | data_holder: Peer::new(capacity, message, index), 32 | client_data: None, 33 | new_client_data: false, 34 | } 35 | } 36 | 37 | /// set manager with the initial values that a local peer holds at the beginning of 38 | /// the protocol session 39 | /// return: first message 40 | pub fn initialize_data(&mut self, peer_id: PeerIdentifier) -> Option { 41 | self.data_holder.set_peer_id(peer_id); 42 | let zero_step_data = self.data_holder.zero_step(peer_id); 43 | self.client_data = zero_step_data; 44 | return self.client_data.clone(); 45 | } 46 | 47 | /// Get the next message this client needs to send 48 | pub fn get_next_message( 49 | &mut self, 50 | from: PeerIdentifier, 51 | payload: MessagePayload, 52 | ) -> Option { 53 | self.data_holder.update_data(from, payload); 54 | self.data_holder.do_step(); 55 | self.data_holder.get_next_item() 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/mmpc-client/src/tendermint_client.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeMap; 2 | use std::net::SocketAddr; 3 | 4 | use crate::peer::{Peer, ProtocolDataManager, MAX_CLIENTS}; 5 | use log::{debug, error, info, warn}; 6 | 7 | use mmpc_server_common::common::*; 8 | use mmpc_server_common::{ 9 | ClientMessage, MessagePayload, MissingMessagesRequest, PeerIdentifier, ProtocolIdentifier, 10 | RelayMessage, ServerMessage, ServerMessageType, ServerResponse, StoredMessages, 11 | }; 12 | 13 | pub struct SessionClient 14 | where 15 | T: Peer, 16 | { 17 | pub state: State, 18 | pub client: tendermint::rpc::Client, 19 | } 20 | 21 | impl SessionClient { 22 | pub fn new( 23 | client_addr: SocketAddr, 24 | server_addr: &tendermint::net::Address, 25 | client_index: u32, 26 | capacity: u32, 27 | message: Vec, 28 | ) -> SessionClient { 29 | let protocol_id = 1; 30 | SessionClient { 31 | state: State::new(protocol_id, capacity, client_addr, client_index, message), 32 | client: tendermint::rpc::Client::new(server_addr).unwrap(), 33 | } 34 | } 35 | } 36 | 37 | impl SessionClient { 38 | pub fn query(&self) -> BTreeMap { 39 | let current_step = self.state.data_manager.data_holder.current_step(); 40 | debug!("Current step {}", current_step); 41 | let capacity = self.state.data_manager.data_holder.capacity(); 42 | debug!("Capacity {}", capacity); 43 | let mut missing_clients = self 44 | .state 45 | .stored_messages 46 | .get_missing_clients_vector(current_step, capacity); 47 | 48 | debug!("Missing: {:?}", missing_clients); 49 | 50 | // No need to query if nothing is missing 51 | if missing_clients.is_empty() { 52 | return BTreeMap::new(); 53 | } 54 | 55 | if missing_clients.len() > MAX_CLIENTS { 56 | missing_clients.truncate(MAX_CLIENTS); 57 | } 58 | debug!("Missing requested: {:?}", missing_clients); 59 | 60 | let request = MissingMessagesRequest { 61 | round: current_step, 62 | missing_clients: missing_clients, 63 | }; 64 | let tx = serde_json::to_string(&request).unwrap(); 65 | match self.client.abci_query(None, tx, None, false) { 66 | Ok(response) => { 67 | let response_log = response.log; 68 | let server_response: BTreeMap = 69 | match serde_json::from_str(&response_log.to_string()) { 70 | Ok(server_response) => server_response, 71 | Err(_) => BTreeMap::new(), 72 | }; 73 | server_response 74 | } 75 | Err(_) => { 76 | warn!("Query not successful, returning empty message"); 77 | BTreeMap::new() 78 | } 79 | } 80 | } 81 | 82 | pub fn register(&mut self, index: u32, capacity: u32, kg_index: i32) -> ServerMessage { 83 | let mut msg = ClientMessage::new(); 84 | let port = 8080 + index; 85 | let client_addr: SocketAddr = format!("127.0.0.1:{}", port).parse().unwrap(); 86 | // No index to begin with 87 | msg.set_register(client_addr, self.state.protocol_id, capacity, kg_index); 88 | 89 | debug!("Register message {:?}", msg); 90 | let tx = 91 | tendermint::abci::transaction::Transaction::new(serde_json::to_string(&msg).unwrap()); 92 | let response = self.client.broadcast_tx_commit(tx).unwrap(); 93 | let server_response = response.clone().deliver_tx.log.unwrap(); 94 | info!("Registered OK"); 95 | debug!("ServerResponse {:?}", server_response); 96 | let server_response: ServerMessage = 97 | serde_json::from_str(&response.deliver_tx.log.unwrap().to_string()).unwrap(); 98 | debug!("ServerResponse {:?}", server_response); 99 | // TODO Add Error checks etc 100 | self.state.registered = true; 101 | return server_response; 102 | } 103 | 104 | pub fn send_message(&self, msg: ClientMessage) -> BTreeMap { 105 | debug!("Sending message {:?}", msg); 106 | let tx = 107 | tendermint::abci::transaction::Transaction::new(serde_json::to_string(&msg).unwrap()); 108 | let server_response = match self.client.broadcast_tx_commit(tx) { 109 | Ok(response) => { 110 | let server_response = response.clone().deliver_tx.log.unwrap(); 111 | debug!("ServerResponse {:?}", server_response); 112 | let server_response: BTreeMap = 113 | serde_json::from_str(&response.deliver_tx.log.unwrap().to_string()).unwrap(); 114 | server_response 115 | } 116 | Err(_) => { 117 | warn!("Unable to include message in block, returning empty response"); 118 | BTreeMap::new() 119 | } 120 | }; 121 | return server_response; 122 | } 123 | 124 | // Stores the server response to the stored messages 125 | pub fn store_server_response(&mut self, messages: &BTreeMap) { 126 | let round = self.state.data_manager.data_holder.current_step(); 127 | for (client_idx, msg) in messages { 128 | self.state 129 | .stored_messages 130 | .update(round, *client_idx, msg.clone()); 131 | } 132 | } 133 | 134 | pub fn handle_relay_message(&mut self, client_msg: ClientMessage) -> Option { 135 | let msg = client_msg.relay_message.unwrap(); 136 | let new_message; 137 | let next = self.state.handle_relay_message(msg.clone()); 138 | match next { 139 | Some(next_msg) => { 140 | new_message = Some(self.state.generate_relay_message(next_msg.clone())); 141 | } 142 | None => { 143 | new_message = Some(ClientMessage::new()); 144 | } 145 | } 146 | new_message 147 | } 148 | 149 | pub fn generate_client_answer(&mut self, msg: ServerMessage) -> Option { 150 | // let last_message = self.state.last_message.clone(); 151 | let mut new_message = None; 152 | let msg_type = msg.msg_type(); 153 | match msg_type { 154 | ServerMessageType::Response => { 155 | let next = self.state.handle_server_response(&msg); 156 | match next { 157 | Ok(next_msg) => { 158 | new_message = Some(next_msg.clone()); 159 | } 160 | Err(_) => { 161 | error!("Error in handle_server_response"); 162 | } 163 | } 164 | } 165 | // TODO: better cases separation, this is a placeholder 166 | ServerMessageType::RelayMessage => { 167 | new_message = Some(ClientMessage::new()); 168 | } 169 | ServerMessageType::Abort => { 170 | info!("Got abort message"); 171 | //Ok(MessageProcessResult::NoMessage) 172 | new_message = Some(ClientMessage::new()); 173 | } 174 | ServerMessageType::Undefined => { 175 | new_message = Some(ClientMessage::new()); 176 | //panic!("Got undefined message: {:?}",msg); 177 | } 178 | }; 179 | new_message 180 | } 181 | } 182 | 183 | /// Inner client state, responsible for parsing server responses and producing the next message 184 | pub struct State 185 | where 186 | T: Peer, 187 | { 188 | pub registered: bool, 189 | pub protocol_id: ProtocolIdentifier, 190 | pub client_addr: SocketAddr, 191 | pub data_manager: ProtocolDataManager, 192 | pub last_message: ClientMessage, 193 | pub bc_dests: Vec, 194 | pub stored_messages: StoredMessages, 195 | } 196 | 197 | impl State { 198 | pub fn new( 199 | protocol_id: ProtocolIdentifier, 200 | capacity: u32, 201 | client_addr: SocketAddr, 202 | client_index: u32, 203 | message: Vec, 204 | ) -> State 205 | where 206 | T: Peer, 207 | { 208 | let data_m: ProtocolDataManager = 209 | ProtocolDataManager::new(capacity, message, client_index); 210 | State { 211 | registered: false, 212 | protocol_id, 213 | client_addr, 214 | last_message: ClientMessage::new(), 215 | bc_dests: vec![0], 216 | data_manager: data_m, 217 | stored_messages: StoredMessages::new(), 218 | } 219 | } 220 | } 221 | 222 | impl State { 223 | fn handle_relay_message(&mut self, relay_msg: RelayMessage) -> Option { 224 | // parse relay message 225 | let from = relay_msg.peer_number; 226 | if from == self.data_manager.data_holder.peer_id() { 227 | debug!("-------self message accepted ------\n "); 228 | } 229 | let payload = relay_msg.message; 230 | self.data_manager.get_next_message(from, payload) 231 | } 232 | 233 | fn generate_relay_message(&self, payload: MessagePayload) -> ClientMessage { 234 | let _msg = ClientMessage::new(); 235 | // create relay message 236 | let mut relay_message = RelayMessage::new( 237 | self.data_manager.data_holder.peer_id(), 238 | self.protocol_id, 239 | self.client_addr, 240 | ); 241 | let to: Vec = self.bc_dests.clone(); 242 | 243 | let mut client_message = ClientMessage::new(); 244 | 245 | relay_message.set_message_params(to, String::from(payload)); 246 | client_message.relay_message = Some(relay_message); 247 | client_message 248 | } 249 | 250 | fn handle_register_response(&mut self, peer_id: PeerIdentifier) -> Result { 251 | info!("Peer identifier: {}", peer_id); 252 | // Set the session parameters 253 | let message = self 254 | .data_manager 255 | .initialize_data(peer_id) 256 | .unwrap_or_else(|| panic!("failed to initialize")); 257 | Ok(self.generate_relay_message(message.clone())) 258 | } 259 | 260 | fn get_last_message(&self) -> Option { 261 | let last_msg = self.last_message.clone(); 262 | return Some(last_msg.clone()); 263 | } 264 | 265 | fn handle_error_response(&mut self, err_msg: &str) -> Result { 266 | match err_msg { 267 | resp if resp == String::from(NOT_YOUR_TURN) => { 268 | let last_msg = self.get_last_message(); 269 | match last_msg { 270 | Some(msg) => { 271 | return Ok(msg.clone()); 272 | } 273 | None => { 274 | panic!("No message to resend"); 275 | } 276 | } 277 | } 278 | not_initialized_resp if not_initialized_resp == String::from(STATE_NOT_INITIALIZED) => { 279 | debug!("Not initialized, sending again"); 280 | let last_msg = self.get_last_message(); 281 | match last_msg { 282 | Some(_) => { 283 | // If protocol is not initialized, wait for a message from the server 284 | return Ok(ClientMessage::new()); 285 | } 286 | None => { 287 | panic!("No message to resend"); 288 | } 289 | } 290 | } 291 | _ => { 292 | warn!("didn't handle error correctly"); 293 | return Err("error response handling failed"); 294 | } 295 | } 296 | } 297 | 298 | fn handle_server_response( 299 | &mut self, 300 | msg: &ServerMessage, 301 | ) -> Result { 302 | let server_response = msg.response.clone().unwrap(); 303 | match server_response { 304 | ServerResponse::Register(peer_id) => { 305 | let client_message = self.handle_register_response(peer_id); 306 | match client_message { 307 | Ok(_msg) => { 308 | debug!("sending peers first message: {:#?}", _msg); 309 | return Ok(_msg.clone()); 310 | } 311 | Err(_) => { 312 | error!("error occured"); 313 | return Ok(ClientMessage::new()); 314 | } 315 | } 316 | } 317 | ServerResponse::ErrorResponse(err_msg) => { 318 | let err_msg_slice: &str = &err_msg[..]; 319 | let msg = self.handle_error_response(err_msg_slice); 320 | match msg { 321 | Ok(_msg) => return Ok(_msg), 322 | Err(_) => { 323 | error!("error occured"); 324 | return Ok(ClientMessage::new()); 325 | } 326 | } 327 | } 328 | ServerResponse::NoResponse => unimplemented!(), 329 | } 330 | } 331 | } 332 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/mmpc-server-common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mmpc-server-common" 3 | version = "0.1.0" 4 | authors = ["Avi ", "Alex Manuskin "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | serde = { version = "1.0", features = ["derive"] } 9 | serde_json = "1.0" 10 | tokio-codec = "0.1" 11 | byteorder = "1.3" 12 | tokio = "0.1" 13 | log = "0.4" 14 | futures = "0.1" 15 | bytes = "0.4" 16 | rand = "0.7" 17 | tokio-jsoncodec = "0.1" 18 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/mmpc-server-common/src/common.rs: -------------------------------------------------------------------------------- 1 | /// common constants and structures for relay communication 2 | use super::MessagePayload; 3 | // Error responses 4 | pub static CANT_REGISTER_RESPONSE: &str = "Can't register peer"; 5 | pub static RELAY_ERROR_RESPONSE: &str = "Can't relay message"; 6 | pub static STATE_NOT_INITIALIZED: &str = "Relay sessions state is not initialized"; 7 | pub static RELAY_MESSAGE_DELIMITER: &str = ":::"; 8 | pub static NOT_YOUR_TURN: &str = "Not this peers turn"; 9 | pub static NOT_A_PEER: &str = "Not a peer"; 10 | 11 | /// eddsa constants 12 | pub static PK_MESSAGE_PREFIX: &str = "PUBLIC_KEY"; 13 | pub static COMMITMENT_MESSAGE_PREFIX: &str = "COMMITMENT"; 14 | pub static R_KEY_MESSAGE_PREFIX: &str = "R_KEY"; 15 | pub static R_KEY_MESSAGE_DELIMITER: &str = "@"; 16 | pub static SIGNATURE_MESSAGE_PREFIX: &str = "SIGNATURE"; 17 | 18 | pub static EMPTY_MESSAGE_PAYLOAD: &str = ""; 19 | 20 | pub fn generate_pk_message_payload(pk: &String) -> MessagePayload { 21 | return format!( 22 | "{}{}{}", 23 | PK_MESSAGE_PREFIX, 24 | RELAY_MESSAGE_DELIMITER, 25 | pk.clone() 26 | ); 27 | } 28 | 29 | pub fn generate_commitment_message_payload(cmtnmt: &String) -> MessagePayload { 30 | return format!( 31 | "{prefix}{delimiter}{message}", 32 | prefix = COMMITMENT_MESSAGE_PREFIX, 33 | delimiter = RELAY_MESSAGE_DELIMITER, 34 | message = cmtnmt.clone() 35 | ); 36 | } 37 | 38 | #[allow(non_snake_case)] 39 | pub fn generate_R_message_payload(r: &String) -> MessagePayload { 40 | return format!( 41 | "{prefix}{delimiter}{message}", 42 | prefix = R_KEY_MESSAGE_PREFIX, 43 | delimiter = RELAY_MESSAGE_DELIMITER, 44 | message = r.clone() 45 | ); 46 | } 47 | 48 | pub fn generate_signature_message_payload(sig: &String) -> MessagePayload { 49 | return format!( 50 | "{prefix}{delimiter}{message}", 51 | prefix = SIGNATURE_MESSAGE_PREFIX, 52 | delimiter = RELAY_MESSAGE_DELIMITER, 53 | message = sig.clone() 54 | ); 55 | } 56 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/mmpc-server-common/src/lib.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::collections::BTreeMap; 3 | use std::net::SocketAddr; 4 | use std::vec::Vec; 5 | use tokio_jsoncodec::Codec as JsonCodec; 6 | 7 | pub mod common; 8 | pub mod protocol; 9 | 10 | pub type ProtocolIdentifier = u32; 11 | pub type PeerIdentifier = u32; 12 | pub type MessagePayload = String; 13 | 14 | const MAX_CLIENTS: u32 = 12; 15 | 16 | #[derive(Debug, Clone, Serialize, Deserialize)] 17 | pub struct RelayMessage { 18 | pub peer_number: PeerIdentifier, 19 | pub protocol_id: ProtocolIdentifier, 20 | pub from: SocketAddr, 21 | pub to: Vec, 22 | pub message: MessagePayload, 23 | } 24 | 25 | impl RelayMessage { 26 | pub fn new( 27 | peer_number: PeerIdentifier, 28 | protocol_id: ProtocolIdentifier, 29 | from: SocketAddr, 30 | ) -> RelayMessage { 31 | RelayMessage { 32 | peer_number, 33 | protocol_id, 34 | from, 35 | to: Vec::new(), 36 | message: String::from(""), 37 | } 38 | } 39 | 40 | pub fn set_message_params>(&mut self, to: Vec, message: S) { 41 | //self.round = round_number; 42 | self.to = to; 43 | self.message = message.into(); 44 | } 45 | } 46 | 47 | #[derive(Debug, Clone, Deserialize, Serialize)] 48 | pub enum ServerResponse { 49 | // Register response containing peer number 50 | Register(PeerIdentifier), 51 | 52 | // Error message 53 | ErrorResponse(String), 54 | 55 | // No response 56 | NoResponse, 57 | } 58 | 59 | #[derive(Default, Clone, Debug, Deserialize, Serialize)] 60 | pub struct AbortMessage { 61 | pub peer_number: PeerIdentifier, 62 | pub protocol_id: ProtocolIdentifier, 63 | } 64 | 65 | impl AbortMessage { 66 | pub fn new(peer_number: PeerIdentifier, protocol_id: ProtocolIdentifier) -> AbortMessage { 67 | AbortMessage { 68 | peer_number, 69 | protocol_id, 70 | } 71 | } 72 | } 73 | 74 | #[derive(Clone, Debug, Deserialize, Serialize)] 75 | pub struct RegisterMessage { 76 | pub addr: SocketAddr, 77 | 78 | pub protocol_id: ProtocolIdentifier, 79 | 80 | pub capacity: u32, 81 | 82 | pub index: i32, 83 | } 84 | 85 | #[derive(Debug, PartialEq)] 86 | pub enum ServerMessageType { 87 | Response, 88 | Abort, 89 | RelayMessage, 90 | Undefined, 91 | } 92 | 93 | #[derive(Default, Clone, Debug, Deserialize, Serialize)] 94 | pub struct ServerMessage { 95 | #[serde(skip_serializing_if = "Option::is_none")] 96 | pub abort: Option, 97 | 98 | #[serde(skip_serializing_if = "Option::is_none")] 99 | pub response: Option, 100 | 101 | #[serde(skip_serializing_if = "Option::is_none")] 102 | pub relay_message: Option, 103 | } 104 | 105 | #[derive(Default, Clone, Debug, Deserialize, Serialize)] 106 | pub struct MissingMessagesRequest { 107 | pub round: u32, 108 | pub missing_clients: Vec, 109 | } 110 | 111 | #[derive(Default, Clone, Debug, Deserialize, Serialize)] 112 | pub struct MissingMessagesReply { 113 | pub missing_messages: BTreeMap, 114 | } 115 | 116 | impl ServerMessage { 117 | pub fn new() -> ServerMessage { 118 | ServerMessage { 119 | response: None, 120 | 121 | abort: None, 122 | 123 | relay_message: None, 124 | } 125 | } 126 | 127 | pub fn msg_type(&self) -> ServerMessageType { 128 | if self.response.is_some() { 129 | return ServerMessageType::Response; 130 | } 131 | if self.relay_message.is_some() { 132 | return ServerMessageType::RelayMessage; 133 | } 134 | if self.abort.is_some() { 135 | return ServerMessageType::Abort; 136 | } 137 | return ServerMessageType::Undefined; 138 | } 139 | } 140 | 141 | #[derive(Default, Debug, Deserialize, Serialize, Clone)] 142 | pub struct StoredMessages { 143 | pub messages: BTreeMap>, 144 | } 145 | 146 | impl StoredMessages { 147 | pub fn new() -> StoredMessages { 148 | StoredMessages { 149 | messages: BTreeMap::new(), 150 | } 151 | } 152 | 153 | // Insert a new ClientMessage for a given round, and a given party 154 | pub fn update(&mut self, round: u32, party: u32, msg: ClientMessage) { 155 | self.messages.entry(round).or_insert(BTreeMap::new()); 156 | match self.messages.get_mut(&round) { 157 | Some(messages) => { 158 | messages.insert(party, msg.clone()); 159 | } 160 | _ => (), 161 | } 162 | } 163 | 164 | // Return the current number of stored messages 165 | pub fn get_number_messages(&self, round: u32) -> usize { 166 | match self.messages.get(&round) { 167 | Some(messages) => return messages.keys().len(), 168 | None => 0, 169 | } 170 | } 171 | 172 | // Returns the messages of the current round as client messages format, 173 | // or an empty vector if no messages are stored for the round 174 | pub fn get_messages_vector_client_message(&self, round: u32) -> Vec { 175 | match self.messages.get(&round) { 176 | Some(round_messages) => { 177 | let mut response_vec = Vec::new(); 178 | for (_client_idx, msg) in round_messages.iter() { 179 | response_vec.push(msg.clone()); 180 | } 181 | return response_vec; 182 | } 183 | None => return Vec::new(), 184 | } 185 | } 186 | 187 | // Returns the messages of the current round as client messages format, 188 | // or an empty hashmap if no messages are stored for the round 189 | pub fn get_messages_map_client_message(&self, round: u32) -> BTreeMap { 190 | match self.messages.get(&round) { 191 | Some(round_messages) => { 192 | let mut response = BTreeMap::new(); 193 | // Only return a response on the first MAX clients 194 | let mut max_counter = 0; 195 | for (client_idx, msg) in round_messages.iter() { 196 | let idx = *client_idx as u32; 197 | response.insert(idx, msg.clone()); 198 | max_counter += 1; 199 | if max_counter > MAX_CLIENTS { 200 | break; 201 | } 202 | } 203 | return response; 204 | } 205 | None => return BTreeMap::new(), 206 | } 207 | } 208 | 209 | // Returns the messages of the current round as client messages format, 210 | // or an empty hashmap if no messages are stored for the round 211 | pub fn get_messages_map_from_vector( 212 | &self, 213 | round: u32, 214 | missing_clients: &[u32], 215 | ) -> BTreeMap { 216 | match self.messages.get(&round) { 217 | Some(round_messages) => { 218 | // TODO: Rewrite with filter and iterator 219 | let mut response_vec = BTreeMap::new(); 220 | for (client_idx, msg) in round_messages.iter() { 221 | let idx = *client_idx as u32; 222 | if missing_clients.contains(&idx) { 223 | response_vec.insert(idx, msg.clone()); 224 | } 225 | } 226 | return response_vec; 227 | } 228 | None => return BTreeMap::new(), 229 | } 230 | } 231 | 232 | // Return a vector of all clients whos messages are not yet stored for a given round 233 | pub fn get_missing_clients_vector(&self, round: u32, capacity: u32) -> Vec { 234 | let return_vec; 235 | match self.messages.get(&round) { 236 | Some(keys) => { 237 | return_vec = (1..capacity + 1) 238 | .filter(|x| !keys.contains_key(x)) 239 | .collect(); 240 | } 241 | None => { 242 | return_vec = (1..capacity + 1).collect(); 243 | } 244 | } 245 | return_vec 246 | } 247 | } 248 | 249 | #[derive(Default, Debug, Deserialize, Serialize, Clone)] 250 | pub struct ClientMessage { 251 | #[serde(skip_serializing_if = "Option::is_none")] 252 | pub register: Option, 253 | 254 | #[serde(skip_serializing_if = "Option::is_none")] 255 | pub abort: Option, 256 | 257 | #[serde(skip_serializing_if = "Option::is_none")] 258 | pub relay_message: Option, 259 | } 260 | 261 | impl ClientMessage { 262 | pub fn new() -> ClientMessage { 263 | ClientMessage { 264 | register: None, 265 | 266 | abort: None, 267 | 268 | relay_message: None, 269 | } 270 | } 271 | 272 | pub fn set_register( 273 | &mut self, 274 | addr: SocketAddr, 275 | protocol_id: ProtocolIdentifier, 276 | capacity: u32, 277 | index: i32, 278 | ) { 279 | self.register = Some(RegisterMessage { 280 | addr, 281 | protocol_id, 282 | capacity, 283 | index, 284 | }); 285 | } 286 | 287 | pub fn is_empty(&self) -> bool { 288 | self.relay_message.is_none() && self.abort.is_none() && self.register.is_none() 289 | } 290 | 291 | pub fn are_equal_payloads(&self, msg: &ClientMessage) -> bool { 292 | if self.register.is_some() && msg.register.is_some() { 293 | return true; 294 | } else if self.relay_message.is_some() && msg.relay_message.is_some() { 295 | let self_message = self.relay_message.clone().unwrap().message; 296 | let message = msg.relay_message.clone().unwrap().message; 297 | return self_message == message; 298 | } else if self.abort.is_some() && msg.abort.is_some() { 299 | return true; 300 | } 301 | false 302 | } 303 | 304 | pub fn msg_type(&self) -> ClientMessageType { 305 | if self.register.is_some() { 306 | return ClientMessageType::Register; 307 | } 308 | if self.relay_message.is_some() { 309 | return ClientMessageType::RelayMessage; 310 | } 311 | if self.abort.is_some() { 312 | return ClientMessageType::Abort; 313 | } 314 | return ClientMessageType::Undefined; 315 | } 316 | } 317 | 318 | #[derive(Debug)] 319 | pub enum ClientMessageType { 320 | Register, 321 | Abort, 322 | RelayMessage, 323 | Undefined, 324 | Test, 325 | } 326 | 327 | #[derive(Default, Debug, Serialize, Deserialize)] 328 | struct RegisterResponse { 329 | peer_number: PeerIdentifier, 330 | } 331 | 332 | // in: clientMessage out:serverMessage 333 | pub type ServerToClientCodec = JsonCodec; 334 | pub type ClientToServerCodec = JsonCodec; 335 | 336 | #[cfg(test)] 337 | mod tests { 338 | use super::ClientMessage; 339 | use super::StoredMessages; 340 | 341 | #[test] 342 | fn test_stored_messages() { 343 | let mut stored_messages = StoredMessages::new(); 344 | stored_messages.update(1, 3, ClientMessage::new()); 345 | stored_messages.update(1, 2, ClientMessage::new()); 346 | } 347 | 348 | #[test] 349 | fn test_get_number_messages() { 350 | let mut stored_messages = StoredMessages::new(); 351 | let round = 1; 352 | stored_messages.update(round, 3, ClientMessage::new()); 353 | stored_messages.update(round, 2, ClientMessage::new()); 354 | assert_eq!(stored_messages.get_number_messages(round), 2); 355 | // Test no messages for a round where none where inserted 356 | assert_eq!(stored_messages.get_number_messages(3), 0); 357 | } 358 | 359 | #[test] 360 | fn test_get_missing_clients_vector() { 361 | let mut stored_messages = StoredMessages::new(); 362 | let round = 1; 363 | let capacity = 4; 364 | stored_messages.update(round, 3, ClientMessage::new()); 365 | stored_messages.update(round, 2, ClientMessage::new()); 366 | assert_eq!( 367 | stored_messages.get_missing_clients_vector(round, capacity), 368 | [1, 4] 369 | ); 370 | // Test an empty round 371 | assert_eq!( 372 | stored_messages.get_missing_clients_vector(round + 1, capacity), 373 | [1, 2, 3, 4] 374 | ); 375 | } 376 | 377 | #[test] 378 | fn test_get_messages_map_client_message() { 379 | let mut stored_messages = StoredMessages::new(); 380 | let round = 1; 381 | stored_messages.update(round, 3, ClientMessage::new()); 382 | stored_messages.update(round, 2, ClientMessage::new()); 383 | let mut i: u32 = 2; 384 | // Assert all messages are stored in order of round and client 385 | for (idx, _) in stored_messages.get_messages_map_client_message(round) { 386 | assert_eq!(i, idx); 387 | i += 1; 388 | } 389 | // Assert sorted order for non sequential client messages 390 | let mut stored_messages = StoredMessages::new(); 391 | stored_messages.update(round, 4, ClientMessage::new()); 392 | stored_messages.update(round, 2, ClientMessage::new()); 393 | let mut i: u32 = 2; 394 | for (idx, _) in stored_messages.get_messages_map_client_message(round) { 395 | assert_eq!(i, idx); 396 | i += 2; 397 | } 398 | // Test for more that MAX clients 399 | let mut stored_messages = StoredMessages::new(); 400 | stored_messages.update(round, 1, ClientMessage::new()); 401 | stored_messages.update(round, 2, ClientMessage::new()); 402 | stored_messages.update(round, 3, ClientMessage::new()); 403 | stored_messages.update(round, 4, ClientMessage::new()); 404 | stored_messages.update(round, 5, ClientMessage::new()); 405 | stored_messages.update(round, 6, ClientMessage::new()); 406 | stored_messages.update(round, 7, ClientMessage::new()); 407 | stored_messages.update(round, 8, ClientMessage::new()); 408 | stored_messages.update(round, 9, ClientMessage::new()); 409 | stored_messages.update(round, 10, ClientMessage::new()); 410 | stored_messages.update(round, 11, ClientMessage::new()); 411 | stored_messages.update(round, 12, ClientMessage::new()); 412 | stored_messages.update(round, 13, ClientMessage::new()); 413 | stored_messages.update(round, 14, ClientMessage::new()); 414 | assert_eq!( 415 | stored_messages 416 | .get_messages_map_client_message(round) 417 | .into_iter() 418 | .len(), 419 | 13 420 | ); 421 | } 422 | 423 | #[test] 424 | fn test_get_messages_from_vector() { 425 | let mut stored_messages = StoredMessages::new(); 426 | let round = 1; 427 | stored_messages.update(round, 3, ClientMessage::new()); 428 | stored_messages.update(round, 2, ClientMessage::new()); 429 | // Assert all messages are stored in order of round and client 430 | println!( 431 | "Stored {:?}", 432 | stored_messages.get_messages_map_from_vector(round, &[2]) 433 | ); 434 | } 435 | } 436 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/mmpc-server-common/src/protocol.rs: -------------------------------------------------------------------------------- 1 | /// Structures for supported protocols for relay-server 2 | use log::debug; 3 | use serde::{Deserialize, Serialize}; 4 | use std::error::Error; 5 | use std::fs::File; 6 | use std::io::BufReader; 7 | use std::sync::{Arc, RwLock}; 8 | 9 | use crate::ProtocolIdentifier; 10 | 11 | static PROTOCOLS_F: &str = r#"./protocols.json"#; 12 | 13 | #[derive(Debug, Clone)] 14 | pub struct ProtocolDescriptor { 15 | pub id: ProtocolIdentifier, 16 | pub capacity: u32, 17 | pub turn: Arc>, 18 | } 19 | 20 | impl ProtocolDescriptor { 21 | pub fn new(id: ProtocolIdentifier, capacity: u32) -> ProtocolDescriptor { 22 | ProtocolDescriptor { 23 | id, 24 | capacity, 25 | turn: Arc::new(RwLock::new(1)), 26 | } 27 | } 28 | 29 | // Advances the peer whose turn it is to transmit. 30 | // If the peer is 0, initializes state to 1, else, advances turn by 1 31 | pub fn advance_turn(&self) -> u32 { 32 | let mut turn = self.turn.write().unwrap(); 33 | let peer_number = (*turn + 1) % (self.capacity + 1); 34 | if peer_number == 0 { 35 | *turn = 1; 36 | } else { 37 | *turn = peer_number; 38 | } 39 | *turn 40 | } 41 | 42 | // Get the # of next peer that can send a message 43 | pub fn next(&self) -> u32 { 44 | *self.turn.read().unwrap() 45 | } 46 | } 47 | 48 | /// Returns true if the protocol is a valid protocol as determined by the 49 | /// protocols.json file 50 | pub fn is_valid_protocol(p: &ProtocolDescriptor) -> bool { 51 | let all_protocols = get_protocols(); 52 | match all_protocols { 53 | Ok(_protocols) => { 54 | for prot in _protocols.protocols { 55 | debug!("Checking if fits protocol: {:?}", prot); 56 | if prot.id == p.id { 57 | if prot.capacities.contains(&(p.capacity)) { 58 | return true; 59 | } else { 60 | return false; 61 | } 62 | } 63 | } 64 | return false; 65 | } 66 | Err(_) => panic!("Corrupt protocols file"), 67 | } 68 | } 69 | 70 | #[derive(Debug, Deserialize, Serialize)] 71 | struct Protocolss { 72 | pub protocols: Vec, 73 | } 74 | 75 | #[derive(Deserialize, Debug, Serialize)] 76 | struct Protocol { 77 | pub id: u32, 78 | pub capacities: Vec, 79 | pub names: Vec, 80 | } 81 | 82 | // Reutrn all avaliable protocols 83 | fn get_protocols() -> Result> { 84 | debug!("Getting protocols"); 85 | 86 | // Open the file in read-only mode with buffer. 87 | let path = PROTOCOLS_F; 88 | let file = File::open(path)?; 89 | let reader = BufReader::new(file); 90 | 91 | // Read the JSON contents of the file as an instance of `Protocols`. 92 | let p = serde_json::from_reader(reader)?; 93 | 94 | //debug!("Got protocols: {:?}", p); 95 | Ok(p) 96 | } 97 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/protocols.json: -------------------------------------------------------------------------------- 1 | { 2 | "protocols":[ 3 | { 4 | "id": 0, 5 | "names": ["test-protocol"], 6 | "capacities": [1, 2, 3, 4, 5, 10, 20, 50, 100] 7 | }, 8 | { 9 | "id": 1, 10 | "names": ["Multi-party-eddsa","multi-party-eddsa", "multi_party_ed25519"], 11 | "capacities": [1, 2, 3, 4, 5, 8,10, 16, 20,30, 32, 40,50, 60,64,70, 80, 90, 96, 100, 110, 120,128,130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 255, 256, 312, 384, 400, 448, 512, 768, 916, 1024] 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/run_exp.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import stat 4 | import subprocess 5 | import time 6 | import csv 7 | 8 | HELP_MESSAGE = """ 9 | Run local kg and sign experiments 10 | """ 11 | 12 | def write_result(parties, write_filename, max_time): 13 | file_exists = os.path.isfile(write_filename) 14 | with open(write_filename, 'a') as csvfile: 15 | fieldnames = ["parties", "time"] 16 | csv_dict = {"parties": parties, "time": max_time} 17 | writer = csv.DictWriter(csvfile, fieldnames=fieldnames) 18 | if not file_exists: 19 | writer.writeheader() # file doesn't exist yet, write a header 20 | writer.writerow(csv_dict) 21 | 22 | def get_max_run_time(parties, read_filename): 23 | print("################ GETTING DATA #######################") 24 | try: 25 | with open(read_filename, mode='r') as csv_file: 26 | times = list() 27 | csv_reader = csv.DictReader(csv_file) 28 | for row in csv_reader: 29 | try: 30 | times.append(int(row["millis"])) 31 | except: 32 | pass 33 | max_time = max(times) 34 | return max_time 35 | except: 36 | return 0 37 | 38 | 39 | def main(): 40 | 41 | def run_exps(exp_type, nodes, parties): 42 | max_vec = list() 43 | for i in range(1): 44 | exp_filename = "./exp-{}-{}.csv".format(exp_type, parties) 45 | try: 46 | os.remove(exp_filename) 47 | except: 48 | pass 49 | subprocess.call(["python", "generate.py", "-n", str(nodes)]) 50 | reset_tool = "./tools/local-cluster-reset-{}.sh".format(nodes) 51 | subprocess.call(["sh", reset_tool]) 52 | sleep_time = max(int(nodes), 10) 53 | # Give time for all nodes to connect 54 | time.sleep(sleep_time) 55 | tool = "./tools/{}-demo.sh".format(exp_type) 56 | subprocess.call(["sh", tool, str(nodes), str(parties)]) 57 | sleep_time = 20 58 | if exp_type is "kg": 59 | sleep_time = max(int(int(parties)/2), 20) 60 | elif exp_type is "sign": 61 | sleep_time = max(int(int(parties) * 1.5), 20) 62 | time.sleep(sleep_time) 63 | write_filename = "./full-exp-{}-{}.csv".format(exp_type, nodes) 64 | val = int(get_max_run_time(parties, exp_filename)) 65 | if val != 0: 66 | max_vec.append(val) 67 | avg = int(sum(max_vec) / len(max_vec)) 68 | write_result(parties, write_filename, avg) 69 | 70 | args = get_args() 71 | #nodes_range = [4, 2, 1] 72 | nodes_range = [10] 73 | #parties_range = [8, 4] 74 | parties_range = range(60, 0, -10) 75 | if args.nodes: 76 | nodes_range = [args.nodes] 77 | if args.parties: 78 | parties_range = [args.parties] 79 | for nodes in nodes_range: 80 | for parties in parties_range: 81 | run_exps("kg", nodes, parties) 82 | run_exps("sign", nodes, parties) 83 | 84 | 85 | def get_args(): 86 | 87 | parser = argparse.ArgumentParser( 88 | description=HELP_MESSAGE, 89 | formatter_class=argparse.RawTextHelpFormatter) 90 | 91 | parser.add_argument('-d', '--debug', 92 | default=False, action='store_true', 93 | help="Output debug log to _s-tui.log") 94 | parser.add_argument('-n', '--nodes', 95 | default=None, 96 | help="Number of nodes to create configs for") 97 | parser.add_argument('-p', '--parties', 98 | default=None, 99 | help="Number of nodes to create configs for") 100 | args = parser.parse_args() 101 | return args 102 | 103 | 104 | if __name__ == '__main__': 105 | main() 106 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/sign-demo.sh: -------------------------------------------------------------------------------- 1 | echo "$0: MP-EDDSA" 2 | #clean 3 | 4 | rm signature? 5 | rm signature?? 6 | rm log*.log 7 | 8 | n=3 9 | 10 | echo "sign part" 11 | for i in $(seq 1 $n); 12 | do 13 | cargo run -p mmpc-client --bin sign-client -- -I $i -C $n -M "message"& 14 | done 15 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/src/bin/server.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of a server designed to work 2 | //! as a relay between Peers communicating in a MPC protocol. 3 | //! A protocol is represented by a unique identifier and a capacity 4 | //! A client that wishes to communicate with othr peers via the server 5 | //! must build its messages in the Codec supplied in relay_server_common lib 6 | //! 7 | //! 8 | //! To run the server: run this file and in another terminal, run: 9 | //! cargo +nightly run --example connect 127.0.0.1:8080 10 | //! this will run a client that utilizes the server in some way 11 | //! 12 | use clap::{App, Arg, ArgMatches}; 13 | use mmpc_server::RelayApp; 14 | use std::io; 15 | use std::net::SocketAddr; 16 | 17 | fn arg_matches<'a>() -> ArgMatches<'a> { 18 | App::new("relay-server") 19 | .arg( 20 | Arg::with_name("address") 21 | // Default tendermint port 22 | .long("address") 23 | .short("A") 24 | .default_value("127.0.0.1:26658") 25 | .value_name(""), 26 | ) 27 | .arg( 28 | Arg::with_name("capacity") 29 | .default_value("2") 30 | .short("P") 31 | .long("participants"), 32 | ) 33 | .arg( 34 | Arg::with_name("verbose") 35 | .short("v") 36 | .long("verbose") 37 | .multiple(true) 38 | .help("Increases logging verbosity each use for up to 3 times"), 39 | ) 40 | .get_matches() 41 | } 42 | 43 | fn setup_logging(verbosity: u64, port: String) -> Result<(), fern::InitError> { 44 | let mut base_config = fern::Dispatch::new(); 45 | 46 | base_config = match verbosity { 47 | 0 => base_config 48 | .level(log::LevelFilter::Info) 49 | .level_for("abci::server", log::LevelFilter::Warn), // filter out abci::server 50 | 1 => base_config 51 | .level(log::LevelFilter::Debug) 52 | .level_for("tokio_core", log::LevelFilter::Warn) // filter out tokio 53 | .level_for("tokio_reactor", log::LevelFilter::Warn) 54 | .level_for("hyper", log::LevelFilter::Warn) 55 | .level_for("abci::server", log::LevelFilter::Warn), 56 | _2_or_more => base_config.level(log::LevelFilter::Trace), 57 | }; 58 | 59 | // Separate file config so we can include year, month and day in file logs 60 | let file_config = fern::Dispatch::new() 61 | .format(|out, message, record| { 62 | out.finish(format_args!( 63 | "{}[{}][{}] {} {}", 64 | chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"), 65 | record.target(), 66 | record.level(), 67 | line!(), 68 | message 69 | )) 70 | }) 71 | .chain(fern::log_file(format!("relay-server-{}.log", port))?); 72 | 73 | let stdout_config = fern::Dispatch::new() 74 | .format(|out, message, record| { 75 | // special format for debug messages coming from our own crate. 76 | if record.level() > log::LevelFilter::Info && record.target() == "relay_server" { 77 | out.finish(format_args!( 78 | "---\nDEBUG: {}: {}\n---", 79 | chrono::Local::now().format("%H:%M:%S"), 80 | message 81 | )) 82 | } else { 83 | out.finish(format_args!( 84 | "[{}][{}][{}] {} ", 85 | chrono::Local::now().format("%H:%M:%S"), 86 | record.target(), 87 | record.level(), 88 | message 89 | )) 90 | } 91 | }) 92 | .chain(io::stdout()); 93 | 94 | base_config 95 | .chain(file_config) 96 | .chain(stdout_config) 97 | .apply()?; 98 | 99 | Ok(()) 100 | } 101 | 102 | fn main() { 103 | let matches = arg_matches(); 104 | 105 | let addr: SocketAddr = matches 106 | .value_of("address") 107 | .unwrap() 108 | .parse() 109 | .expect("Unable to parse socket address"); 110 | 111 | let capacity: u32 = matches 112 | .value_of("capacity") 113 | .unwrap() 114 | .parse() 115 | .expect("Invalid number of participants"); 116 | 117 | let port = addr.port().to_string(); 118 | 119 | let verbosity: u64 = matches.occurrences_of("verbose"); 120 | 121 | setup_logging(verbosity, port).expect("failed to initialize logging."); 122 | 123 | abci::run(addr, RelayApp::new(capacity)); 124 | } 125 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod relay_app; 2 | mod relay_session; 3 | 4 | pub use crate::relay_app::RelayApp; 5 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/src/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "message_direction": "client2server", //enum [one of client2server and server2client] 3 | "register": { // object, optional 4 | "protocol_id": 4 // integer 5 | }, 6 | "relay_message": { // object, optional 7 | "peer_number": 2, // integer 8 | "protocol_id": 4, // integer 9 | "round_number": 10, // integer 10 | "to": [1, 3, 5], // array 11 | "message": { //object 12 | "message_content": "0x141" //string 13 | } 14 | }, 15 | "abort": { // object, optional 16 | "peer_number": 2 // integer 17 | } 18 | } 19 | 20 | { 21 | "message_direction": "server2client", //enum [one of client2server and server2client] 22 | "abort": { // object, optional 23 | "peer_number": 2 // integer, optional 24 | }, 25 | "response":{ //object, optional 26 | "register_response": { // object , optional 27 | "peer_number": 2 // integer 28 | }, 29 | "error_response": { //object, optional 30 | "err_message": "Error, not peer X's turn" 31 | }, 32 | "general_response": { //object, optional 33 | "response_text": "general purpose" //string, optional 34 | } 35 | }, 36 | "relay_message": { // object, optional 37 | "peer_number": 2, // integer (from) 38 | "protocol_id": 4, // integer 39 | "round_number": 10, // integer 40 | "to": [1, 3, 5], // array 41 | "message": { //object 42 | "message_content": "0x141" //string 43 | } 44 | } 45 | } 46 | 47 | ===> 48 | 49 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/src/relay_app.rs: -------------------------------------------------------------------------------- 1 | use crate::relay_session::RelaySession; 2 | use abci::{ 3 | RequestCheckTx, RequestDeliverTx, RequestQuery, ResponseCheckTx, ResponseDeliverTx, 4 | ResponseQuery, 5 | }; 6 | use log::{debug, info, warn}; 7 | use mmpc_server_common::protocol::ProtocolDescriptor; 8 | use mmpc_server_common::{ 9 | ClientMessage, ClientMessageType, MissingMessagesRequest, ServerMessage, ServerResponse, 10 | }; 11 | 12 | const MAX_CLIENTS: usize = 12; 13 | 14 | pub struct RelayApp { 15 | relay_session: RelaySession, 16 | } 17 | 18 | impl RelayApp { 19 | pub fn new(capacity: u32) -> RelayApp { 20 | RelayApp { 21 | relay_session: RelaySession::new(capacity), 22 | } 23 | } 24 | } 25 | 26 | // Convert incoming tx data to the proper BigEndian size. txs.len() > 8 will return 0 27 | fn convert_tx(bytes: &[u8]) -> String { 28 | String::from_utf8(bytes.to_vec()).expect("Found invalid UTF-8") 29 | } 30 | 31 | impl RelayApp { 32 | fn can_relay(&self, client_message: &ClientMessage) -> u32 { 33 | match client_message.msg_type() { 34 | ClientMessageType::RelayMessage => { 35 | let msg = client_message.clone().relay_message.unwrap(); 36 | let can_relay = self.relay_session.can_relay(&msg.from, &msg); 37 | match can_relay { 38 | Ok(()) => debug!("Can relay this message"), 39 | _ => (), 40 | } 41 | } 42 | _ => (), 43 | } 44 | 0 45 | } 46 | 47 | fn is_valid(&self, client_message: &ClientMessage) -> u32 { 48 | match client_message.msg_type() { 49 | ClientMessageType::Register => { 50 | let register = client_message.clone().register.unwrap(); 51 | info!( 52 | "Got register message. protocol id requested: {}", 53 | register.protocol_id 54 | ); 55 | let protocol_descriptor = 56 | ProtocolDescriptor::new(register.protocol_id, register.capacity); 57 | if self 58 | .relay_session 59 | .can_register(®ister.addr, protocol_descriptor) 60 | { 61 | 0 62 | } else { 63 | 1 64 | } 65 | } 66 | ClientMessageType::RelayMessage => { 67 | // TODO: Check validity of relay message here 68 | 0 69 | } 70 | _ => unimplemented!("This is not yet implemented"), 71 | } 72 | } 73 | } 74 | 75 | impl abci::Application for RelayApp { 76 | fn check_tx(&mut self, req: &RequestCheckTx) -> ResponseCheckTx { 77 | let mut resp = ResponseCheckTx::new(); 78 | let c = convert_tx(req.get_tx()); 79 | debug!("CheckTX: Received {:?}", c); 80 | let client_message: ClientMessage = serde_json::from_slice(req.get_tx()).unwrap(); 81 | debug!("Value is {:?}", client_message); 82 | resp.set_code(self.is_valid(&client_message)); 83 | resp 84 | } 85 | 86 | fn deliver_tx(&mut self, req: &RequestDeliverTx) -> ResponseDeliverTx { 87 | let mut resp = ResponseDeliverTx::new(); 88 | let c = convert_tx(req.get_tx()); 89 | info!("DeliverTX: Received {:?}", c); 90 | let client_message: ClientMessage = serde_json::from_slice(req.get_tx()).unwrap(); 91 | info!("Value is {:?} In DeliverTx", client_message); 92 | 93 | debug!("Message type is {:?}", client_message.msg_type()); 94 | 95 | match client_message.msg_type() { 96 | ClientMessageType::Register => { 97 | if self.is_valid(&client_message) != 0 { 98 | resp.set_code(1); 99 | return resp; 100 | } 101 | let register = client_message.register.unwrap(); 102 | warn!( 103 | "Got register message. protocol id requested: {}", 104 | register.protocol_id 105 | ); 106 | let client_index = self 107 | .relay_session 108 | .register_new_peer( 109 | register.addr, 110 | register.protocol_id, 111 | register.capacity, 112 | register.index, 113 | ) 114 | .unwrap(); 115 | resp.set_code(0); 116 | info!("Setting data to {:?}", resp.data); 117 | let mut server_msg = ServerMessage::new(); 118 | server_msg.response = Some(ServerResponse::Register(client_index)); 119 | // TODO: Currently using log and not data, data is expecting a different encoding, 120 | // sigh 121 | resp.set_log(serde_json::to_string(&server_msg).unwrap().to_owned()); 122 | } 123 | ClientMessageType::RelayMessage => { 124 | let relay_msg = client_message.clone().relay_message.unwrap(); 125 | let peer_id = relay_msg.peer_number; 126 | info!("Got relay message from {}", peer_id); 127 | if self.can_relay(&client_message) == 0 { 128 | debug!("I can relay this") 129 | } 130 | let round = self.relay_session.round(); 131 | self.relay_session 132 | .update_stored_messages(round, peer_id, client_message); 133 | info!("Stored message of client {}", peer_id); 134 | 135 | let response = self 136 | .relay_session 137 | .stored_messages() 138 | .get_messages_map_client_message(round); 139 | resp.set_log(serde_json::to_string(&response).unwrap().to_owned()); 140 | debug!("Response log {:?}", resp.log); 141 | self.relay_session 142 | .try_increase_round(self.relay_session.protocol().capacity); 143 | // If received a message from each party, increase round 144 | debug!("Response log {:?}", resp.log); 145 | } 146 | _ => unimplemented!("This is not yet implemented"), 147 | } 148 | 149 | resp 150 | } 151 | 152 | fn query(&mut self, req: &RequestQuery) -> ResponseQuery { 153 | let mut resp = ResponseQuery::new(); 154 | 155 | let missing_messages: MissingMessagesRequest = serde_json::from_slice(&req.data).unwrap(); 156 | debug!("Query: Received {:?}", missing_messages); 157 | 158 | // TODO: Error handle 159 | let requested_round = missing_messages.round; 160 | let mut missing_clients = missing_messages.missing_clients; 161 | debug!("Requested round {}", requested_round); 162 | 163 | let stored_messages = self.relay_session.stored_messages(); 164 | // debug!("Query: All Stored Messages: {:?}", stored_messages); 165 | 166 | if missing_clients.len() > MAX_CLIENTS { 167 | missing_clients.truncate(MAX_CLIENTS); 168 | } 169 | let response = 170 | stored_messages.get_messages_map_from_vector(requested_round, &missing_clients); 171 | 172 | debug!("Server response {:?}", response); 173 | 174 | resp.set_log(serde_json::to_string(&response).unwrap().to_owned()); 175 | debug!("Response log {:?}", resp.log); 176 | 177 | resp.set_code(0); 178 | resp.set_index(-1); 179 | resp.set_height(1_i64); 180 | resp 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/src/relay_session.rs: -------------------------------------------------------------------------------- 1 | use log::{debug, info, warn}; 2 | use std::collections::HashMap; 3 | use std::net::SocketAddr; 4 | use std::sync::{Arc, RwLock}; 5 | 6 | use mmpc_server_common::{ClientMessage, StoredMessages}; 7 | use mmpc_server_common::{PeerIdentifier, ProtocolIdentifier, RelayMessage}; 8 | 9 | use mmpc_server_common::protocol::ProtocolDescriptor; 10 | 11 | #[derive(Clone, Debug)] 12 | pub struct Peer { 13 | pub peer_id: PeerIdentifier, 14 | pub addr: SocketAddr, 15 | pub registered: bool, 16 | } 17 | 18 | impl Peer { 19 | pub fn new(addr: SocketAddr) -> Peer { 20 | Peer { 21 | peer_id: 0, 22 | addr: addr, 23 | registered: false, 24 | } 25 | } 26 | } 27 | 28 | #[derive(Debug, Clone, PartialEq)] 29 | pub enum RelaySessionState { 30 | Empty, 31 | 32 | Uninitialized, 33 | 34 | Initialized, 35 | } 36 | 37 | #[derive(Debug, Clone)] 38 | pub struct RelaySession { 39 | peers: Arc>>, 40 | 41 | active_peers: Arc>, 42 | 43 | protocol: Arc>, 44 | 45 | state: Arc>, 46 | 47 | round: Arc>, 48 | 49 | stored_messages: Arc>, 50 | } 51 | 52 | impl RelaySession { 53 | /// Returns the current number of active peers. 54 | /// If a peer disconnects, it should be removed from the active peers 55 | fn get_number_of_active_peers(&self) -> u32 { 56 | self.peers 57 | .read() 58 | .unwrap() 59 | .iter() 60 | .filter(|(_, p)| p.registered) 61 | .fold(0, |acc, _| acc + 1) 62 | } 63 | 64 | /// Register a new peer to this relay session 65 | /// after adding this address as a peer, 66 | /// the state might change to either Uninitialized (if this is the first peer registering) 67 | /// or Initialized (meaning session has reached the required # of participants) 68 | pub fn register_new_peer( 69 | &self, 70 | addr: SocketAddr, 71 | protocol_id: ProtocolIdentifier, 72 | capacity: u32, 73 | index: i32, 74 | ) -> Option { 75 | let _addr = &addr; 76 | let number_of_active_peers = self.get_number_of_active_peers(); 77 | 78 | let protocol_descriptor = ProtocolDescriptor::new(protocol_id, capacity); 79 | debug!("-----------------PEERS: {:?}---------------", self.peers); 80 | if self.can_register(_addr, protocol_descriptor) { 81 | let mut peer = Peer::new(addr); 82 | peer.registered = true; 83 | peer.peer_id = number_of_active_peers + 1; 84 | 85 | self.peers.write().unwrap().insert(addr, peer); 86 | 87 | // activate this connection as a peer 88 | // if needed, set the ProtocolDescriptor for this sessuib 89 | // and change the state 90 | let state = self.state(); 91 | if let RelaySessionState::Empty = state { 92 | self.set_protocol(ProtocolDescriptor::new(protocol_id, capacity)); 93 | info!("Relay session state is now Uninitialized"); 94 | self.set_state(RelaySessionState::Uninitialized); 95 | } 96 | //if self.protocol.clone().into_inner().capacity == number_of_active_peers + 1 { 97 | if self.protocol().capacity == number_of_active_peers + 1 { 98 | info!("Relay session state is now Initialized"); 99 | self.set_state(RelaySessionState::Initialized); 100 | } 101 | info!("Registered peer {}", number_of_active_peers + 1); 102 | if index == -1 { 103 | Some(number_of_active_peers + 1) //peer_id 104 | } else { 105 | Some(index as u32) //peer_id 106 | } 107 | } else { 108 | warn!("Unable to register {:}", addr); // error 109 | None 110 | } 111 | } 112 | 113 | /// Checks if it is possible for this address 114 | /// to register as a peer in this session 115 | pub fn can_register(&self, _addr: &SocketAddr, protocol: ProtocolDescriptor) -> bool { 116 | match self.state() { 117 | // if this is the first peer to register 118 | // check that the protocol is valid 119 | RelaySessionState::Empty => { 120 | debug!("Checking if protocol description is valid"); 121 | if !mmpc_server_common::protocol::is_valid_protocol(&protocol) { 122 | warn!("Protocol is invalid"); 123 | 124 | return false; 125 | } 126 | } 127 | // if there is already a set protocol, 128 | // check that the peer wants to register to the set protocol 129 | RelaySessionState::Uninitialized => { 130 | debug!("Checking if protocol description is same as at protocol description"); 131 | let prot = self.protocol(); 132 | if !(prot.id == protocol.id && prot.capacity == protocol.capacity) { 133 | warn!("Protocol description does not fit current configuration"); 134 | return false; 135 | } 136 | } 137 | _ => { 138 | debug!("Relay session state is neither empty nor uninitialized "); 139 | return false; 140 | } 141 | } 142 | true 143 | } 144 | } 145 | 146 | impl RelaySession { 147 | /// Creates a new Relay Session with default (empty) fields 148 | /// and an Empty state 149 | pub fn new(capacity: u32) -> RelaySession { 150 | RelaySession { 151 | peers: Arc::new(RwLock::new(HashMap::new())), 152 | 153 | active_peers: Arc::new(RwLock::new(0)), 154 | 155 | protocol: Arc::new(RwLock::new( 156 | mmpc_server_common::protocol::ProtocolDescriptor::new(0, capacity), 157 | )), 158 | 159 | state: Arc::new(RwLock::new(RelaySessionState::Empty)), 160 | 161 | round: Arc::new(RwLock::new(0)), 162 | 163 | stored_messages: Arc::new(RwLock::new(StoredMessages::new())), 164 | } 165 | } 166 | 167 | /// Check if this relay message sent from the given SocketAddr 168 | /// and is valid to send to rest of the peers 169 | pub fn can_relay(&self, _from: &SocketAddr, msg: &RelayMessage) -> Result<(), &'static str> { 170 | debug!("Checking if {:} can relay", msg.peer_number); 171 | debug!("Server state: {:?}", self.state()); 172 | debug!("Turn of peer #: {:}", self.protocol().next()); 173 | 174 | // TODO: Add some checks of what messages can be stored 175 | 176 | return Ok(()); 177 | } 178 | 179 | // Return the current state of the relay session 180 | pub fn state(&self) -> RelaySessionState { 181 | self.state.read().unwrap().clone() 182 | } 183 | 184 | // Set the current relay session state to a new state 185 | pub fn set_state(&self, new_state: RelaySessionState) { 186 | *self.state.write().unwrap() = new_state; 187 | } 188 | 189 | pub fn protocol(&self) -> ProtocolDescriptor { 190 | self.protocol.read().unwrap().clone() 191 | } 192 | 193 | pub fn set_protocol(&self, protocol: ProtocolDescriptor) { 194 | *self.protocol.write().unwrap() = protocol; 195 | } 196 | 197 | pub fn round(&self) -> u32 { 198 | self.round.read().unwrap().clone() 199 | } 200 | 201 | pub fn update_stored_messages(&mut self, round: u32, party: u32, msg: ClientMessage) { 202 | self.stored_messages 203 | .write() 204 | .unwrap() 205 | .update(round, party, msg); 206 | } 207 | 208 | pub fn stored_messages(&self) -> StoredMessages { 209 | self.stored_messages.read().unwrap().clone() 210 | } 211 | 212 | pub fn try_increase_round(&self, capacity: u32) { 213 | if self 214 | .stored_messages 215 | .read() 216 | .unwrap() 217 | .get_number_messages(self.round.read().unwrap().clone()) 218 | == capacity as usize 219 | { 220 | *self.round.write().unwrap() += 1; 221 | } 222 | } 223 | } 224 | 225 | #[cfg(test)] 226 | mod tests { 227 | use super::RelaySession; 228 | use super::RelaySessionState; 229 | 230 | use mmpc_server_common::protocol::ProtocolDescriptor; 231 | use mmpc_server_common::ProtocolIdentifier; 232 | 233 | use std::net::SocketAddr; 234 | use std::sync::Arc; 235 | use std::thread; 236 | 237 | #[test] 238 | fn test_add_peer() { 239 | let protocol_id: ProtocolIdentifier = 1; 240 | let capacity: u32 = 1; 241 | let rs = RelaySession::new(capacity); 242 | let client_addr: SocketAddr = format!("127.0.0.1:808{}", 0).parse().unwrap(); 243 | 244 | let peer_num = rs.register_new_peer(client_addr, protocol_id, capacity, 0); 245 | assert_eq!(peer_num, Some(1)); 246 | } 247 | 248 | #[test] 249 | fn test_add_multi_peers() { 250 | let protocol_id: ProtocolIdentifier = 1; 251 | let capacity: u32 = 5; 252 | let rs = RelaySession::new(capacity); 253 | 254 | let mut peer_num: u32 = 0; 255 | for i in 0..capacity { 256 | let client_addr: SocketAddr = format!("127.0.0.1:808{}", i).parse().unwrap(); 257 | peer_num = rs 258 | .register_new_peer(client_addr, protocol_id, capacity, 0) 259 | .expect("Unable to register"); 260 | println!("Peer number is {}", peer_num); 261 | } 262 | 263 | assert_eq!(peer_num, capacity); 264 | } 265 | 266 | #[test] 267 | fn test_add_multi_peers_in_parallel() { 268 | let mut children = vec![]; 269 | 270 | let protocol_id: ProtocolIdentifier = 1; 271 | let capacity: u32 = 50; 272 | let rs = Arc::new(RelaySession::new(capacity)); 273 | 274 | for i in 0..capacity { 275 | let rs_inner = Arc::clone(&rs); 276 | 277 | let client_addr: SocketAddr = format!("127.0.0.1:80{}", 30 + i).parse().unwrap(); 278 | children.push(thread::spawn(move || { 279 | rs_inner 280 | .register_new_peer(client_addr, protocol_id, capacity, -1) 281 | .expect("Unable to register"); 282 | })); 283 | } 284 | 285 | for child in children { 286 | let _ = child.join(); 287 | } 288 | let rs_inner = Arc::clone(&rs); 289 | let number_of_active_peers = rs_inner.get_number_of_active_peers(); 290 | assert_eq!(number_of_active_peers, capacity); 291 | } 292 | 293 | #[test] 294 | fn test_can_register_protocol_valid() { 295 | let client_addr: SocketAddr = "127.0.0.1:8081".to_string().parse().unwrap(); 296 | let protocol_id: ProtocolIdentifier = 1 as ProtocolIdentifier; 297 | let capacity: u32 = 5; 298 | let protocol_descriptor = ProtocolDescriptor::new(protocol_id, capacity); 299 | let rs = RelaySession::new(capacity); 300 | assert!(rs.can_register(&client_addr, protocol_descriptor)) 301 | } 302 | 303 | #[test] 304 | fn test_can_register_protocol_invalid() { 305 | let client_addr: SocketAddr = "127.0.0.1:8081".to_string().parse().unwrap(); 306 | let protocol_id: ProtocolIdentifier = 100 as ProtocolIdentifier; 307 | let capacity: u32 = 5; 308 | let protocol_descriptor = ProtocolDescriptor::new(protocol_id, capacity); 309 | let rs = RelaySession::new(capacity); 310 | assert!(!rs.can_register(&client_addr, protocol_descriptor)) 311 | } 312 | 313 | /////////////////////////// test register /////////////////////////////////// 314 | #[test] 315 | fn test_register_state() { 316 | let protocol_id: ProtocolIdentifier = 1; 317 | let capacity: u32 = 4; 318 | let rs = RelaySession::new(capacity); 319 | 320 | // State is empty at first 321 | assert_eq!(RelaySessionState::Empty, rs.state()); 322 | for i in 0..capacity - 1 { 323 | let client_addr: SocketAddr = format!("127.0.0.1:808{}", i).parse().unwrap(); 324 | rs.register_new_peer(client_addr, protocol_id, capacity, -1); 325 | // State is not initialized when not all are connected 326 | assert_eq!(RelaySessionState::Uninitialized, rs.state()); 327 | } 328 | let client_addr: SocketAddr = format!("127.0.0.1:808{}", capacity - 1).parse().unwrap(); 329 | let messages = rs.register_new_peer(client_addr, protocol_id, capacity, -1); 330 | // Once all are connected, state should initialize 331 | assert_eq!(RelaySessionState::Initialized, rs.state()); 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/tests/test_relay_server.rs: -------------------------------------------------------------------------------- 1 | //use futures::sync::mpsc; 2 | //use relay_server::Client; 3 | //use relay_server::RelayServer; 4 | //use relay_server_common::ProtocolIdentifier; 5 | //use std::net::SocketAddr; 6 | 7 | #[test] 8 | fn test_server_add_peer() { 9 | assert_eq!(1, 1); 10 | } 11 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/tools/kg-demo.sh: -------------------------------------------------------------------------------- 1 | echo "$0: MP-EDDSA" 2 | #clean 3 | 4 | rm keys* 5 | rm log-kg*.log 6 | rm log-error*.log 7 | 8 | 9 | # First argument is the number fo nodes in the cluseter 10 | n=${1:-4} 11 | # Second argument is the number of parties 12 | k=${2:-4} 13 | 14 | cargo build --all 15 | 16 | echo "keygen part" 17 | for i in $(seq 1 $k); 18 | do 19 | S=$(( ( RANDOM % $n ) )) 20 | PORT=$(( 46057 + $S * 100 )) 21 | #PORT="46157" 22 | # cargo run -p mmpc-client --bin kg-client -- -I $i -C $n --proxy 127.0.0.1:$PORT -v & 23 | #./target/debug/kg-client -I $i -C $k --proxy 127.0.0.1:$PORT &> log-error$i.log & 24 | ./target/debug/kg-client -I $i -C $k --proxy 127.0.0.1:$PORT & 25 | done 26 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/tools/sign-demo.sh: -------------------------------------------------------------------------------- 1 | echo "$0: MP-EDDSA" 2 | #clean 3 | 4 | rm signature* 5 | rm log-sign*.log 6 | rm log-error*.log 7 | 8 | # First argument is the number fo nodes in the cluseter 9 | n=${1:-4} 10 | # Second argument is the number of parties 11 | k=${2:-4} 12 | 13 | echo "sign part" 14 | for i in $(seq 1 $k); 15 | do 16 | S=$(( ( RANDOM % $n ) )) 17 | PORT=$(( 46057 + $S * 100 )) 18 | # cargo run -p mmpc-client --bin sign-client -- -I $i -C $n -M "message" --proxy 127.0.0.1:$PORT & 19 | ./target/debug/sign-client -I $i -C $k -M "message" --proxy 127.0.0.1:$PORT & 20 | done 21 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTendermintServer/use-cases.md: -------------------------------------------------------------------------------- 1 | # Use cases of the system and desired behaviour: 2 | 3 | ## New client connecting to a new session 4 | * Check if protocol is supported 5 | * Open a new relay-session for the client 6 | * Generate a new session identifier 7 | * Store the clients idetifier (this will be later used to idetify the relevant session) 8 | 9 | ## New client connecting to an existing session 10 | * Client provides a relay session idetifier 11 | * Register client as part of the relay session 12 | 13 | ## Runnig protocol 14 | ### 15 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | */target/ 4 | /target/ 5 | common/target/ 6 | 7 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 8 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 9 | Cargo.lock 10 | 11 | # These are backup files generated by rustfmt 12 | **/*.rs.bk 13 | .*.swp 14 | 15 | 16 | # IDE 17 | .idea 18 | .DS_Store 19 | .vscode/ 20 | *rusty-tags.vi 21 | */rusty-tags.vi 22 | 23 | 24 | keys* 25 | signature* 26 | 27 | # Log files 28 | *.log 29 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-server" 3 | version = "0.1.0" 4 | authors = ["Avi ", "Alex Manuskin "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | serde = "1.0" 9 | serde_derive = "1.0" 10 | serde_json = "1.0" 11 | futures = "0.1" 12 | tokio-core = "0.1" 13 | tokio-io = "0.1" 14 | tokio = "0.1" 15 | tokio-codec = "0.1" 16 | tokio-jsoncodec = "0.1" 17 | byteorder = "1.3" 18 | dict = "0.1.5" 19 | chrono = "0.4" 20 | hex = "0.3.2" 21 | structopt = "0.2" 22 | log = "0.4" 23 | rand = "0.7" 24 | clap = "2.33" 25 | fern = "0.5" 26 | 27 | 28 | relay-server-common = { path = "../EddsaTokioServer/relay-server-common" } 29 | 30 | multi-party-ed25519 = { git = "https://github.com/KZen-networks/multi-party-eddsa" } 31 | 32 | [dependencies.curv] 33 | git = "https://github.com/KZen-networks/curv" 34 | features=["ec_ed25519"] 35 | 36 | [lib] 37 | name = "relay_server" 38 | path = "src/lib.rs" 39 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/README.md: -------------------------------------------------------------------------------- 1 | **To Run 2p-EdDSA** 2 | 3 | 1. Run the server : `cargo run --package relay-server --bin server` 4 | 5 | 2. Run keygen: `cargo run --example eddsa_key_gen_client 127.0.0.1:8080 keys1` where keys1 is the party output keys 6 | you should take `apk` for the public key to generate to address from. pay attention to use `keys2` when you run the second instance 7 | (you can choose different names instead of `keys1` and `keys2` ) 8 | 9 | 3. Run signing: `cargo run --example eddsa_sign_client 127.0.0.1:8080 keys1 message` 10 | where `message` is the message to sign. Run another instance for the second party with `keys2` 11 | 12 | 4. the output will be a file with (R,s). the file is called `signature` 13 | 14 | Alternatively, run `./keygen.sh` for keygen and `./sign.sh message` where `message` is the message to sign (see demo gif below) 15 | 16 | ![demo](demo/2P-EdDSA%20demo.gif) 17 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/demo/2P-EdDSA demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZenGo-X/white-city/eada16e95964fbaf23ca86e2251789bfa6e57bfd/RelayProofsOfConcept/EddsaTokioServer/demo/2P-EdDSA demo.gif -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/examples/connect.rs: -------------------------------------------------------------------------------- 1 | /// Implementation of a client that communicates with the relay server 2 | /// this implememnataion is simplistic and used for POC and development and debugging of the 3 | /// server 4 | use std::env; 5 | use std::net::SocketAddr; 6 | 7 | use std::sync::Arc; 8 | use tokio; 9 | use tokio::codec::Framed; 10 | use tokio::net::TcpStream; 11 | 12 | use futures::sync::mpsc; 13 | use futures::{Future, Sink, Stream}; 14 | 15 | use relay_server_common::{ 16 | ClientMessage, ClientToServerCodec, PeerIdentifier, ProtocolIdentifier, RelayMessage, 17 | ServerMessage, ServerMessageType, ServerResponse, 18 | }; 19 | 20 | // ClientSession holds session data 21 | #[derive(Default, Debug, Clone)] 22 | struct ProtocolSession { 23 | pub registered: bool, 24 | pub peer_id: PeerIdentifier, 25 | pub protocol_id: ProtocolIdentifier, 26 | pub next_message: Option, 27 | } 28 | 29 | impl ProtocolSession { 30 | pub fn new() -> ProtocolSession { 31 | ProtocolSession { 32 | registered: false, 33 | peer_id: 0, 34 | protocol_id: 0, 35 | next_message: None, 36 | } 37 | } 38 | } 39 | 40 | #[derive(Default, Debug, Clone)] 41 | struct Client { 42 | pub session: ProtocolSession, 43 | } 44 | 45 | impl Client { 46 | pub fn new() -> Client { 47 | Client { 48 | session: ProtocolSession::new(), 49 | } 50 | } 51 | } 52 | 53 | pub enum MessageProcessResult { 54 | Message, 55 | NoMessage, 56 | Abort, 57 | } 58 | 59 | impl Client { 60 | pub fn respond_to_server( 61 | &self, 62 | msg: ServerMessage, 63 | // A sender to pass messages to be written back to the server 64 | tx: mpsc::Sender, 65 | ) -> Box + Send> { 66 | let response = self.handle_server_response(&msg).unwrap(); 67 | println!("Returning {:?}", response); 68 | if response.is_empty() { 69 | Box::new(futures::future::ok(())) 70 | } else { 71 | Box::new(tx.clone().send(response.clone()).then(|_| Ok(()))) 72 | } 73 | } 74 | 75 | pub fn handle_server_response( 76 | &self, 77 | msg: &ServerMessage, 78 | ) -> Result { 79 | println!("Got message from server: {:?}", msg); 80 | let msg_type = msg.msg_type(); 81 | match msg_type { 82 | ServerMessageType::Response => { 83 | // we expect to receive a register response here 84 | let server_response = msg.response.clone().unwrap(); 85 | match server_response { 86 | ServerResponse::Register(peer_id) => { 87 | println!("Peer identifier: {}", peer_id); 88 | // create a mock relay message 89 | let mut client_message = ClientMessage::new(); 90 | let mut relay_message = 91 | RelayMessage::new(peer_id, self.session.protocol_id); 92 | let mut to: Vec = Vec::new(); 93 | if peer_id == 2 { 94 | to.push(1); 95 | } else { 96 | to.push(2); 97 | } 98 | 99 | relay_message.set_message_params(to, format!("Hi from {}", peer_id)); 100 | client_message.relay_message = Some(relay_message.clone()); 101 | return Ok(client_message); 102 | } 103 | _ => panic!("failed to register"), 104 | } 105 | } 106 | ServerMessageType::RelayMessage => { 107 | println!("Got new relay message"); 108 | println!("{:?}", msg.relay_message.clone().unwrap()); 109 | //Ok(MessageProcessResult::NoMessage) 110 | Ok(ClientMessage::new()) 111 | } 112 | ServerMessageType::Abort => { 113 | println!("Got abort message"); 114 | //Ok(MessageProcessResult::NoMessage) 115 | Ok(ClientMessage::new()) 116 | } 117 | ServerMessageType::Undefined => Ok(ClientMessage::new()), 118 | } 119 | } 120 | 121 | pub fn generate_register_message(&self) -> ClientMessage { 122 | let mut msg = ClientMessage::new(); 123 | msg.register(self.session.protocol_id.clone(), 2); 124 | msg 125 | } 126 | } 127 | 128 | fn main() { 129 | let args = env::args().skip(1).collect::>(); 130 | // Parse what address we're going to connect to 131 | let addr = args 132 | .first() 133 | .unwrap_or_else(|| panic!("This program requires at least one argument")); 134 | 135 | let addr = addr.parse::().unwrap(); 136 | 137 | // Create the event loop and initiate the connection to the remote server 138 | let tcp = TcpStream::connect(&addr); 139 | 140 | let session: Arc = Arc::new(Client::new()); 141 | 142 | let client = Arc::clone(&session); 143 | let handshake = tcp.and_then(move |stream| { 144 | let handshake_io = Framed::new(stream, ClientToServerCodec::new(false)); 145 | let msg = client.generate_register_message(); 146 | handshake_io 147 | .send(msg) 148 | .map(|handshake_io| handshake_io.into_inner()) 149 | .map_err(|e| e.into()) 150 | }); 151 | 152 | let run_client = handshake 153 | .and_then(move |socket| { 154 | let client = Arc::clone(&session); 155 | let _msg = client.generate_register_message(); 156 | 157 | let (to_server, from_server) = 158 | Framed::new(socket, ClientToServerCodec::new(false)).split(); 159 | let (tx, rx) = mpsc::channel(0); 160 | let reader = from_server.for_each(move |msg| { 161 | println!("Received {:?}", msg); 162 | client.respond_to_server(msg, tx.clone()) 163 | }); 164 | 165 | let writer = rx 166 | .map_err(|()| unreachable!("rx can't fail")) 167 | .fold(to_server, |to_server, msg| to_server.send(msg)) 168 | .map(|_| ()); 169 | 170 | reader 171 | .select(writer) 172 | .map(|_| println!("Closing connection")) 173 | .map_err(|(err, _)| err.into()) 174 | }) 175 | .map_err(|e| println!("Error: {}", e)); 176 | 177 | tokio::run(run_client); 178 | } 179 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/keygen.sh: -------------------------------------------------------------------------------- 1 | 2 | echo "$0: MP-EDDSA" 3 | #clean 4 | 5 | 6 | rm keys?? 7 | 8 | kill -9 $(lsof -t -i:8080) 9 | 10 | n=2 11 | 12 | echo "keygen part" 13 | cargo run --package relay-server --bin server -- -P $n & 14 | sleep 2 15 | for i in $(seq 1 $n); 16 | do 17 | cargo run --example eddsa_key_gen_client -- 127.0.0.1:8080 "keys$i" -P $n & 18 | sleep 1 19 | done 20 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/protocols.json: -------------------------------------------------------------------------------- 1 | { 2 | "protocols":[ 3 | { 4 | "id": 0, 5 | "names": ["test-protocol"], 6 | "capacities": [1, 2] 7 | }, 8 | { 9 | "id": 1, 10 | "names": ["Multi-party-eddsa","multi-party-eddsa", "multi_party_ed25519"], 11 | "capacities": [1, 2, 3, 4, 5, 10, 20, 50] 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/relay-server-common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "relay-server-common" 3 | version = "0.1.0" 4 | authors = ["Avi ", "Alex Manuskin "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | serde = { version = "1.0", features = ["derive"] } 9 | serde_json = "1.0" 10 | tokio-codec = "0.1" 11 | byteorder = "1.3" 12 | tokio = "0.1" 13 | log = "0.4" 14 | futures = "0.1" 15 | bytes = "0.4" 16 | rand = "0.7" 17 | tokio-jsoncodec = "0.1" 18 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/relay-server-common/src/common.rs: -------------------------------------------------------------------------------- 1 | /// common constants and structures for relay communication 2 | use super::MessagePayload; 3 | // Error responses 4 | pub static CANT_REGISTER_RESPONSE: &str = "Can't register peer"; 5 | pub static RELAY_ERROR_RESPONSE: &str = "Can't relay message"; 6 | pub static STATE_NOT_INITIALIZED: &str = "Relay sessions state is not initialized"; 7 | pub static RELAY_MESSAGE_DELIMITER: &str = ":::"; 8 | pub static NOT_YOUR_TURN: &str = "Not this peers turn"; 9 | pub static NOT_A_PEER: &str = "Not a peer"; 10 | 11 | /// eddsa constants 12 | pub static PK_MESSAGE_PREFIX: &str = "PUBLIC_KEY"; 13 | pub static COMMITMENT_MESSAGE_PREFIX: &str = "COMMITMENT"; 14 | pub static R_KEY_MESSAGE_PREFIX: &str = "R_KEY"; 15 | pub static R_KEY_MESSAGE_DELIMITER: &str = "@"; 16 | pub static SIGNATURE_MESSAGE_PREFIX: &str = "SIGNATURE"; 17 | 18 | pub static EMPTY_MESSAGE_PAYLOAD: &str = ""; 19 | 20 | pub fn generate_pk_message_payload(pk: &String) -> MessagePayload { 21 | return format!( 22 | "{}{}{}", 23 | PK_MESSAGE_PREFIX, 24 | RELAY_MESSAGE_DELIMITER, 25 | pk.clone() 26 | ); 27 | } 28 | 29 | pub fn generate_commitment_message_payload(cmtnmt: &String) -> MessagePayload { 30 | return format!( 31 | "{prefix}{delimiter}{message}", 32 | prefix = COMMITMENT_MESSAGE_PREFIX, 33 | delimiter = RELAY_MESSAGE_DELIMITER, 34 | message = cmtnmt.clone() 35 | ); 36 | } 37 | 38 | #[allow(non_snake_case)] 39 | pub fn generate_R_message_payload(r: &String) -> MessagePayload { 40 | return format!( 41 | "{prefix}{delimiter}{message}", 42 | prefix = R_KEY_MESSAGE_PREFIX, 43 | delimiter = RELAY_MESSAGE_DELIMITER, 44 | message = r.clone() 45 | ); 46 | } 47 | 48 | pub fn generate_signature_message_payload(sig: &String) -> MessagePayload { 49 | return format!( 50 | "{prefix}{delimiter}{message}", 51 | prefix = SIGNATURE_MESSAGE_PREFIX, 52 | delimiter = RELAY_MESSAGE_DELIMITER, 53 | message = sig.clone() 54 | ); 55 | } 56 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/relay-server-common/src/lib.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::vec::Vec; 3 | use tokio_jsoncodec::Codec as JsonCodec; 4 | 5 | pub mod common; 6 | pub mod protocol; 7 | 8 | pub type ProtocolIdentifier = u32; 9 | pub type PeerIdentifier = u32; 10 | pub type MessagePayload = String; 11 | 12 | #[derive(Debug, Clone, Serialize, Deserialize)] 13 | pub struct RelayMessage { 14 | pub peer_number: PeerIdentifier, 15 | pub protocol_id: ProtocolIdentifier, 16 | //pub round: u32, 17 | pub to: Vec, 18 | pub message: MessagePayload, 19 | } 20 | 21 | impl RelayMessage { 22 | pub fn new(peer_number: PeerIdentifier, protocol_id: ProtocolIdentifier) -> RelayMessage { 23 | RelayMessage { 24 | peer_number, 25 | protocol_id, 26 | to: Vec::new(), 27 | message: String::from(""), 28 | } 29 | } 30 | 31 | pub fn set_message_params>(&mut self, to: Vec, message: S) { 32 | //self.round = round_number; 33 | self.to = to; 34 | self.message = message.into(); 35 | } 36 | } 37 | 38 | #[derive(Debug, Clone, Deserialize, Serialize)] 39 | pub enum ServerResponse { 40 | // Register response containing peer number 41 | Register(PeerIdentifier), 42 | 43 | // Error message 44 | ErrorResponse(String), 45 | 46 | // No response 47 | NoResponse, 48 | } 49 | 50 | #[derive(Default, Clone, Debug, Deserialize, Serialize)] 51 | pub struct AbortMessage { 52 | pub peer_number: PeerIdentifier, 53 | pub protocol_id: ProtocolIdentifier, 54 | } 55 | 56 | impl AbortMessage { 57 | pub fn new(peer_number: PeerIdentifier, protocol_id: ProtocolIdentifier) -> AbortMessage { 58 | AbortMessage { 59 | peer_number, 60 | protocol_id, 61 | } 62 | } 63 | } 64 | 65 | #[derive(Default, Clone, Debug, Deserialize, Serialize)] 66 | pub struct RegisterMessage { 67 | pub protocol_id: ProtocolIdentifier, 68 | 69 | pub capacity: u32, 70 | } 71 | 72 | #[derive(Debug, PartialEq)] 73 | pub enum ServerMessageType { 74 | Response, 75 | Abort, 76 | RelayMessage, 77 | Undefined, 78 | } 79 | 80 | #[derive(Default, Clone, Debug, Deserialize, Serialize)] 81 | pub struct ServerMessage { 82 | #[serde(skip_serializing_if = "Option::is_none")] 83 | pub abort: Option, 84 | 85 | #[serde(skip_serializing_if = "Option::is_none")] 86 | pub response: Option, 87 | 88 | #[serde(skip_serializing_if = "Option::is_none")] 89 | pub relay_message: Option, 90 | } 91 | 92 | impl ServerMessage { 93 | pub fn new() -> ServerMessage { 94 | ServerMessage { 95 | response: None, 96 | 97 | abort: None, 98 | 99 | relay_message: None, 100 | } 101 | } 102 | 103 | pub fn msg_type(&self) -> ServerMessageType { 104 | if self.response.is_some() { 105 | return ServerMessageType::Response; 106 | } 107 | if self.relay_message.is_some() { 108 | return ServerMessageType::RelayMessage; 109 | } 110 | if self.abort.is_some() { 111 | return ServerMessageType::Abort; 112 | } 113 | return ServerMessageType::Undefined; 114 | } 115 | } 116 | 117 | #[derive(Default, Debug, Deserialize, Serialize, Clone)] 118 | pub struct ClientMessage { 119 | #[serde(skip_serializing_if = "Option::is_none")] 120 | pub register: Option, 121 | 122 | #[serde(skip_serializing_if = "Option::is_none")] 123 | pub abort: Option, 124 | 125 | #[serde(skip_serializing_if = "Option::is_none")] 126 | pub relay_message: Option, 127 | } 128 | 129 | impl ClientMessage { 130 | pub fn new() -> ClientMessage { 131 | ClientMessage { 132 | register: None, 133 | 134 | abort: None, 135 | 136 | relay_message: None, 137 | } 138 | } 139 | 140 | pub fn register(&mut self, protocol_id: ProtocolIdentifier, capacity: u32) { 141 | self.register = Some(RegisterMessage { 142 | protocol_id, 143 | capacity, 144 | }); 145 | } 146 | 147 | pub fn is_empty(&self) -> bool { 148 | self.relay_message.is_none() && self.abort.is_none() && self.register.is_none() 149 | } 150 | 151 | pub fn are_equal_payloads(&self, msg: &ClientMessage) -> bool { 152 | if self.register.is_some() && msg.register.is_some() { 153 | return true; 154 | } else if self.relay_message.is_some() && msg.relay_message.is_some() { 155 | let self_message = self.relay_message.clone().unwrap().message; 156 | let message = msg.relay_message.clone().unwrap().message; 157 | return self_message == message; 158 | } else if self.abort.is_some() && msg.abort.is_some() { 159 | return true; 160 | } 161 | false 162 | } 163 | 164 | pub fn msg_type(&self) -> ClientMessageType { 165 | if self.register.is_some() { 166 | return ClientMessageType::Register; 167 | } 168 | if self.relay_message.is_some() { 169 | return ClientMessageType::RelayMessage; 170 | } 171 | if self.abort.is_some() { 172 | return ClientMessageType::Abort; 173 | } 174 | return ClientMessageType::Undefined; 175 | } 176 | } 177 | 178 | #[derive(Debug)] 179 | pub enum ClientMessageType { 180 | Register, 181 | Abort, 182 | RelayMessage, 183 | Undefined, 184 | Test, 185 | } 186 | 187 | #[derive(Default, Debug, Serialize, Deserialize)] 188 | struct RegisterResponse { 189 | peer_number: PeerIdentifier, 190 | } 191 | 192 | // in: clientMessage out:serverMessage 193 | pub type ServerToClientCodec = JsonCodec; 194 | pub type ClientToServerCodec = JsonCodec; 195 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/relay-server-common/src/protocol.rs: -------------------------------------------------------------------------------- 1 | /// Structures for supported protocols for relay-server 2 | use log::debug; 3 | use serde::{Deserialize, Serialize}; 4 | use std::error::Error; 5 | use std::fs::File; 6 | use std::io::BufReader; 7 | use std::sync::{Arc, RwLock}; 8 | 9 | use crate::ProtocolIdentifier; 10 | 11 | static PROTOCOLS_F: &str = r#"./protocols.json"#; 12 | 13 | #[derive(Debug, Clone)] 14 | pub struct ProtocolDescriptor { 15 | pub id: ProtocolIdentifier, 16 | pub capacity: u32, 17 | pub turn: Arc>, 18 | } 19 | 20 | impl ProtocolDescriptor { 21 | pub fn new(id: ProtocolIdentifier, capacity: u32) -> ProtocolDescriptor { 22 | ProtocolDescriptor { 23 | id, 24 | capacity, 25 | turn: Arc::new(RwLock::new(1)), 26 | } 27 | } 28 | 29 | // Advances the peer whose turn it is to transmit. 30 | // If the peer is 0, initializes state to 1, else, advances turn by 1 31 | pub fn advance_turn(&self) -> u32 { 32 | let mut turn = self.turn.write().unwrap(); 33 | let peer_number = (*turn + 1) % (self.capacity + 1); 34 | if peer_number == 0 { 35 | *turn = 1; 36 | } else { 37 | *turn = peer_number; 38 | } 39 | *turn 40 | } 41 | 42 | // Get the # of next peer that can send a message 43 | pub fn next(&self) -> u32 { 44 | *self.turn.read().unwrap() 45 | } 46 | } 47 | 48 | /// Returns true if the protocol is a valid protocol as determined by the 49 | /// protocols.json file 50 | pub fn is_valid_protocol(p: &ProtocolDescriptor) -> bool { 51 | let all_protocols = get_protocols(); 52 | match all_protocols { 53 | Ok(_protocols) => { 54 | for prot in _protocols.protocols { 55 | debug!("Checking if fits protocol: {:?}", prot); 56 | if prot.id == p.id { 57 | if prot.capacities.contains(&(p.capacity)) { 58 | return true; 59 | } else { 60 | return false; 61 | } 62 | } 63 | } 64 | return false; 65 | } 66 | Err(_) => panic!("Corrupt protocols file"), 67 | } 68 | } 69 | 70 | #[derive(Debug, Deserialize, Serialize)] 71 | struct Protocolss { 72 | pub protocols: Vec, 73 | } 74 | 75 | #[derive(Deserialize, Debug, Serialize)] 76 | struct Protocol { 77 | pub id: u32, 78 | pub capacities: Vec, 79 | pub names: Vec, 80 | } 81 | 82 | // Reutrn all avaliable protocols 83 | fn get_protocols() -> Result> { 84 | debug!("Getting protocols"); 85 | 86 | // Open the file in read-only mode with buffer. 87 | let path = PROTOCOLS_F; 88 | let file = File::open(path)?; 89 | let reader = BufReader::new(file); 90 | 91 | // Read the JSON contents of the file as an instance of `Protocols`. 92 | let p = serde_json::from_reader(reader)?; 93 | 94 | //debug!("Got protocols: {:?}", p); 95 | Ok(p) 96 | } 97 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/relay-server.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/sign.sh: -------------------------------------------------------------------------------- 1 | echo "$0: MP-EDDSA" 2 | #clean 3 | 4 | rm signature?? 5 | 6 | kill -9 $(lsof -t -i:8080) 7 | 8 | n=2 9 | 10 | echo "signing part" 11 | cargo run --package relay-server --bin server -- -P $n& 12 | sleep 2 13 | for i in $(seq 1 $n); 14 | do 15 | cargo run --example eddsa_sign_client -- 127.0.0.1:8080 "keys$i" -P $n $1 & 16 | sleep 1 17 | done 18 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/src/bin/server.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of a server designed to work 2 | //! as a relay between Peers communicating in a MPC protocol. 3 | //! A protocol is represented by a unique identifier and a capacity 4 | //! A client that wishes to communicate with othr peers via the server 5 | //! must build its messages in the Codec supplied in relay_server_common lib 6 | //! 7 | //! 8 | //! To run the server: run this file and in another terminal, run: 9 | //! cargo +nightly run --example connect 127.0.0.1:8080 10 | //! this will run a client that utilizes the server in some way 11 | //! 12 | use clap::{App, Arg, ArgMatches}; 13 | use relay_server::RelayServer; 14 | use std::io; 15 | use std::net::SocketAddr; 16 | 17 | fn arg_matches<'a>() -> ArgMatches<'a> { 18 | App::new("relay-server") 19 | .arg( 20 | Arg::with_name("address") 21 | .default_value("127.0.0.1:8080") 22 | .value_name(""), 23 | ) 24 | .arg( 25 | Arg::with_name("capacity") 26 | .default_value("2") 27 | .short("P") 28 | .long("participants"), 29 | ) 30 | .arg( 31 | Arg::with_name("verbose") 32 | .short("v") 33 | .long("verbose") 34 | .multiple(true) 35 | .help("Increases logging verbosity each use for up to 3 times"), 36 | ) 37 | .get_matches() 38 | } 39 | 40 | fn setup_logging(verbosity: u64) -> Result<(), fern::InitError> { 41 | let mut base_config = fern::Dispatch::new(); 42 | 43 | base_config = match verbosity { 44 | 0 => base_config.level(log::LevelFilter::Info), 45 | 1 => base_config 46 | .level(log::LevelFilter::Debug) 47 | .level_for("tokio_core", log::LevelFilter::Warn) // filter out tokio 48 | .level_for("tokio_reactor", log::LevelFilter::Warn), 49 | _2_or_more => base_config.level(log::LevelFilter::Trace), 50 | }; 51 | 52 | // Separate file config so we can include year, month and day in file logs 53 | let file_config = fern::Dispatch::new() 54 | .format(|out, message, record| { 55 | out.finish(format_args!( 56 | "{}[{}][{}] {} {}", 57 | chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"), 58 | record.target(), 59 | record.level(), 60 | line!(), 61 | message 62 | )) 63 | }) 64 | .chain(fern::log_file("relay-server.log")?); 65 | 66 | let stdout_config = fern::Dispatch::new() 67 | .format(|out, message, record| { 68 | // special format for debug messages coming from our own crate. 69 | if record.level() > log::LevelFilter::Info && record.target() == "relay_server" { 70 | out.finish(format_args!( 71 | "---\nDEBUG: {}: {}\n---", 72 | chrono::Local::now().format("%H:%M:%S"), 73 | message 74 | )) 75 | } else { 76 | out.finish(format_args!( 77 | "[{}][{}][{}] {} ", 78 | chrono::Local::now().format("%H:%M:%S"), 79 | record.target(), 80 | record.level(), 81 | message 82 | )) 83 | } 84 | }) 85 | .chain(io::stdout()); 86 | 87 | base_config 88 | .chain(file_config) 89 | .chain(stdout_config) 90 | .apply()?; 91 | 92 | Ok(()) 93 | } 94 | 95 | fn main() { 96 | let matches = arg_matches(); 97 | 98 | let addr: SocketAddr = matches 99 | .value_of("address") 100 | .unwrap() 101 | .parse() 102 | .expect("Unable to parse socket address"); 103 | 104 | let capacity: u32 = matches 105 | .value_of("capacity") 106 | .unwrap() 107 | .parse() 108 | .expect("Invalid number of participants"); 109 | 110 | let verbosity: u64 = matches.occurrences_of("verbose"); 111 | 112 | setup_logging(verbosity).expect("failed to initialize logging."); 113 | 114 | let server = RelayServer::new(addr); 115 | server.start_server(capacity); 116 | } 117 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod relay_server; 2 | mod relay_session; 3 | 4 | pub use crate::relay_server::RelayServer; 5 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/src/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "message_direction": "client2server", //enum [one of client2server and server2client] 3 | "register": { // object, optional 4 | "protocol_id": 4 // integer 5 | }, 6 | "relay_message": { // object, optional 7 | "peer_number": 2, // integer 8 | "protocol_id": 4, // integer 9 | "round_number": 10, // integer 10 | "to": [1, 3, 5], // array 11 | "message": { //object 12 | "message_content": "0x141" //string 13 | } 14 | }, 15 | "abort": { // object, optional 16 | "peer_number": 2 // integer 17 | } 18 | } 19 | 20 | { 21 | "message_direction": "server2client", //enum [one of client2server and server2client] 22 | "abort": { // object, optional 23 | "peer_number": 2 // integer, optional 24 | }, 25 | "response":{ //object, optional 26 | "register_response": { // object , optional 27 | "peer_number": 2 // integer 28 | }, 29 | "error_response": { //object, optional 30 | "err_message": "Error, not peer X's turn" 31 | }, 32 | "general_response": { //object, optional 33 | "response_text": "general purpose" //string, optional 34 | } 35 | }, 36 | "relay_message": { // object, optional 37 | "peer_number": 2, // integer (from) 38 | "protocol_id": 4, // integer 39 | "round_number": 10, // integer 40 | "to": [1, 3, 5], // array 41 | "message": { //object 42 | "message_content": "0x141" //string 43 | } 44 | } 45 | } 46 | 47 | ===> 48 | 49 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/src/relay_server.rs: -------------------------------------------------------------------------------- 1 | use futures::stream; 2 | use futures::sync::mpsc; 3 | use futures::{Future, Sink, Stream}; 4 | use log::{debug, error, info, warn}; 5 | use std::net::SocketAddr; 6 | use std::sync::Arc; 7 | 8 | use tokio::codec::Framed; 9 | use tokio::net::TcpListener; 10 | 11 | use crate::relay_session::{Client, RelaySession}; 12 | use relay_server_common::{ClientMessageType, ServerMessage, ServerToClientCodec}; 13 | 14 | pub struct RelayServer { 15 | pub rs: Option, 16 | addr: std::net::SocketAddr, 17 | } 18 | 19 | impl RelayServer { 20 | pub fn new(addr: SocketAddr) -> RelayServer { 21 | RelayServer { 22 | rs: None, 23 | addr: addr, 24 | } 25 | } 26 | 27 | /// Starts the relay server 28 | pub fn start_server(&self, capacity: u32) { 29 | // Create the event loop and TCP listener we'll accept connections on. 30 | // let mut core = Core::new().unwrap(); 31 | // let handle = core.handle(); 32 | 33 | let listener = TcpListener::bind(&self.addr).unwrap(); 34 | info!("Listening on: {}", &self.addr); 35 | 36 | // Create the session fot the relay server 37 | // TODO: Relay sessions should start when a new client connects 38 | let relay_session = Arc::new(RelaySession::new(capacity)); 39 | 40 | let srv = listener 41 | .incoming() 42 | .for_each(move |socket| { 43 | // Got a new connection 44 | info!("Server got a new connection"); 45 | // TODO TODO TODO 46 | let addr = socket.peer_addr().unwrap(); 47 | 48 | // Frame the socket with JSON codec 49 | //let framed_socket = ServerToClientCodec::new(false).framed(socket); 50 | let framed_socket = Framed::new(socket, ServerToClientCodec::new(false)); 51 | 52 | // obtain a clone of the RelaySession 53 | let relay_session_inner = Arc::clone(&relay_session); //relay_session.clone(); 54 | 55 | // create a channel of communication with the (potential) peer 56 | let (tx, rx) = mpsc::channel(0); 57 | 58 | // insert this client to the servers active_connections 59 | relay_session_inner.insert_new_connection(addr.clone(), Client::new(tx)); 60 | 61 | // split the socket to reading part (stream) and writing part (sink) 62 | let (to_client, from_client) = framed_socket.split(); 63 | 64 | // define future for receiving half 65 | let relay_session_inner = Arc::clone(&relay_session); 66 | let reader = from_client.for_each(move |msg| { 67 | let msg_type = msg.msg_type(); 68 | 69 | // this is our main logic for receiving messages from peer 70 | match msg_type { 71 | ClientMessageType::Register => { 72 | let register = msg.register.unwrap(); 73 | info!( 74 | "Got register message. protocol id requested: {}", 75 | register.protocol_id 76 | ); 77 | let messages_to_send = relay_session_inner.register( 78 | addr, 79 | register.protocol_id, 80 | register.capacity, 81 | ); 82 | RelayServer::send_messages(&messages_to_send) 83 | } 84 | ClientMessageType::RelayMessage => { 85 | let peer = relay_session_inner 86 | .get_peer_by_address(&addr) 87 | .unwrap_or_else(|| panic!("not a peer")); 88 | info!("Got relay message from {}", peer.peer_id); 89 | let relay_msg = msg.relay_message.unwrap().clone(); 90 | let messages_to_send = 91 | relay_session_inner.relay_message(&addr, relay_msg); 92 | RelayServer::send_messages(&messages_to_send) 93 | } 94 | ClientMessageType::Abort => { 95 | let peer = relay_session_inner 96 | .get_peer_by_address(&addr) 97 | .unwrap_or_else(|| panic!("not a peer")); 98 | debug!("Got abort message from {}", peer.peer_id); 99 | let messages_to_send = relay_session_inner.abort(addr); 100 | RelayServer::send_messages(&messages_to_send) 101 | } 102 | ClientMessageType::Test => { 103 | let sender = relay_session_inner 104 | .get_sender_by_address(&addr) 105 | .unwrap_or_else(|| panic!("not a peer")); 106 | let msg = ServerMessage::new(); 107 | RelayServer::send_single_message(sender, msg) 108 | } 109 | ClientMessageType::Undefined => { 110 | warn!("Got unknown or empty message"); 111 | let messages_to_send = relay_session_inner.abort(addr); 112 | RelayServer::send_messages(&messages_to_send) 113 | } 114 | } 115 | }); 116 | 117 | // define future for sending half 118 | let writer = rx 119 | .map_err(|()| unreachable!("rx can't fail")) 120 | // fold on a stream (rx) takes an initial value (to_client, a Sink) 121 | // and run the given closure, for each value passed from the stream (message to send to 122 | // the client) 123 | .fold(to_client, |to_client, msg| to_client.send(msg)) 124 | // this map will cleanly drop the writing half of the socket when done with all processing 125 | .map(|_| ()); 126 | 127 | // if any of the reading/writing half is done - the whole connection is finished 128 | // this makes select a sensible combinator 129 | let connection = reader.select(writer); 130 | 131 | // map & map_err here are used for the case reading half or writing half is dropped 132 | // in which case we will be dropping the other half as well 133 | let relay_session_inner = Arc::clone(&relay_session); 134 | tokio::spawn( 135 | connection 136 | .map(|_| ()) 137 | .map_err(|(err, _)| { 138 | error!("ERROR OCCURED: {:?}", err); 139 | err 140 | }) 141 | .then(move |_| { 142 | // connection is closed 143 | warn!("Disconnected"); 144 | 145 | // this means either a peer disconnected - same as abort, 146 | // or an active connection closed - which is allowed 147 | let messages_to_send = relay_session_inner.abort(addr); 148 | RelayServer::send_messages(&messages_to_send) 149 | }), 150 | ); 151 | 152 | Ok(()) 153 | }) 154 | .map_err(|e| debug!("Error occured {}", e)); 155 | 156 | // execute server 157 | tokio::run(srv); 158 | } 159 | 160 | // Recieves a vector of tuples, of a message and a Sink, 161 | // Sends the message to the the Sink 162 | pub fn send_messages( 163 | messages_to_send: &Vec<(ServerMessage, mpsc::Sender)>, 164 | ) -> Box + Send> { 165 | let sends = messages_to_send 166 | .iter() 167 | .map(|(msg, sink)| sink.clone().send(msg.clone())); 168 | let send_stream = stream::futures_unordered(sends).then(|_| Ok(())); 169 | Box::new(send_stream.for_each(|()| Ok(()))) 170 | } 171 | 172 | // Send a Server message to a specific Sink 173 | pub fn send_single_message( 174 | tx: mpsc::Sender, 175 | response: ServerMessage, 176 | ) -> Box + Send> { 177 | let sends = vec![tx.clone().send(response.clone())]; 178 | let send_stream = stream::futures_unordered(sends).then(|_| Ok(())); 179 | Box::new(send_stream.for_each(|()| Ok(()))) 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/EddsaTokioServer/tests/test_relay_server.rs: -------------------------------------------------------------------------------- 1 | //use futures::sync::mpsc; 2 | //use relay_server::Client; 3 | //use relay_server::RelayServer; 4 | //use relay_server_common::ProtocolIdentifier; 5 | //use std::net::SocketAddr; 6 | 7 | #[test] 8 | fn test_server_add_peer() { 9 | assert_eq!(1, 1); 10 | } 11 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/Formal-spec/TLA+/RelayServer.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZenGo-X/white-city/eada16e95964fbaf23ca86e2251789bfa6e57bfd/RelayProofsOfConcept/Formal-spec/TLA+/RelayServer.pdf -------------------------------------------------------------------------------- /RelayProofsOfConcept/Formal-spec/TLA+/RelayServer.tla: -------------------------------------------------------------------------------- 1 | ---------------------------- MODULE RelayServer ---------------------------- 2 | 3 | EXTENDS Integers 4 | 5 | CONSTANT 6 | PARTIES, \* The set of parties, i.e p1,p2,p3 7 | ROUNDS \* The set of rounds, i.e 1,2,3,4 8 | 9 | ASSUME ROUNDS \subseteq Nat 10 | 11 | VARIABLES 12 | partyState, \* partyState[p] is the state of party r. 13 | serverState, \* The state of the server. 14 | readyParties, \* The set of parties that signal they are ready 15 | assignedParties, \* The set of parties that the server assigned them ID 16 | msgs 17 | \* In the protocol, processes communicate with one another by sending 18 | \* messages. For simplicity, we represent message passing with the 19 | \* variable msgs whose value is the set of all messages that have been 20 | \* sent. A message is sent by adding it to the set msgs. An action 21 | \* that, in an implementation, would be enabled by the receipt of a 22 | \* certain message is here enabled by the presence of that message in 23 | \* msgs. For simplicity, messages are never removed from msgs. This 24 | \* allows a single message to be received by multiple receivers. 25 | ----------------------------------------------------------------------------- 26 | 27 | Messages == 28 | [type : {"Abort","Start"}] 29 | \cup [type : {"Ready"}, party : PARTIES] 30 | \cup [type : {"Assign"}, party : PARTIES] 31 | \cup [type : {"AbortReq"}, party : PARTIES] 32 | 33 | \cup [type: {"P2P"}, from: PARTIES ,to: PARTIES, round: ROUNDS \ {0}] 34 | \cup [type: {"RelayP2P"}, from: PARTIES ,to: PARTIES, round: ROUNDS \ {0}] 35 | \cup [type: {"Broadcast"}, party: PARTIES, round: ROUNDS \ {0}] 36 | \cup [type: {"RelayBroadcast"}, party: PARTIES, round: ROUNDS \ {0}] 37 | 38 | ----------------------------------------------------------------------------- 39 | 40 | \* The type-correctness invariant 41 | TypeOK == 42 | /\ partyState \in [PARTIES -> {"idle", "ready", "assigned", "aborted"}] 43 | /\ serverState \in {"init", "running"} 44 | /\ readyParties \subseteq PARTIES 45 | /\ assignedParties \subseteq PARTIES 46 | /\ msgs \subseteq Messages 47 | ----------------------------------------------------------------------------- 48 | 49 | \* The initial predicate. 50 | Init == 51 | /\ partyState = [p \in PARTIES |-> "idle"] 52 | /\ serverState = "init" 53 | /\ readyParties = {} 54 | /\ assignedParties = {} 55 | /\ msgs = {} 56 | ----------------------------------------------------------------------------- 57 | 58 | \* At first, joining parties must signal the server 59 | PartyReady(p) == 60 | /\ serverState = "init" 61 | /\ msgs' = msgs \cup {[type |-> "Ready", party |-> p]} 62 | /\ p \notin readyParties 63 | /\ readyParties' = readyParties \cup {p} 64 | /\ partyState' = [partyState EXCEPT ![p] = "ready"] 65 | /\ UNCHANGED <> 66 | 67 | \* The server will assign and send ID to each party that sent a signal ready 68 | Assign(p) == 69 | /\ serverState = "init" 70 | /\ [type |-> "Ready", party |-> p] \in msgs 71 | /\ [type |-> "Assign", party |-> p] \notin msgs 72 | /\ msgs' = msgs \cup {[type |-> "Assign", party |-> p]} 73 | /\ assignedParties' = assignedParties \cup {p} 74 | /\ partyState' = [partyState EXCEPT ![p] = "assigned"] 75 | /\ UNCHANGED <> 76 | 77 | \* Once |assigned parties| == N where N (PARTIES) 78 | \* is the constant the server know that represents 79 | \* the number of parties in the protocol then the 80 | \* server changes his state and starts the protocol 81 | Start == 82 | /\ serverState = "init" 83 | /\ assignedParties = PARTIES 84 | /\ serverState' = "running" 85 | /\ msgs' = msgs \cup {[type |-> "Start"]} 86 | /\ UNCHANGED <> 87 | 88 | \* When the protocol runs each party can send abort to the server 89 | PartyAbort(p) == 90 | /\ partyState[p] = "assigned" 91 | /\ partyState' = [partyState EXCEPT ![p] = "aborted"] 92 | /\ [type |-> "AbortReq", party |-> p] \in msgs 93 | /\ serverState = "running" 94 | /\ serverState' = "init" 95 | /\ msgs' = {[type |-> "Abort"]} 96 | /\ UNCHANGED <> 97 | 98 | 99 | \* The server upon receiving abort will stop the protocol and return all state to INIT 100 | Abort == 101 | /\ serverState = "init" 102 | /\ [type |-> "Abort"] \in msgs 103 | /\ readyParties' = {} 104 | /\ msgs' = {} 105 | /\ partyState' = [p \in PARTIES |-> "idle"] 106 | /\ UNCHANGED <> 107 | 108 | 109 | \* When the protocol runs each party can ask the server once every round 110 | \* to relay a broadcast message. Notice there is no enforcing of the order 111 | \* of rounds 112 | ReqToBroadcast(r,p) == 113 | /\ assignedParties = PARTIES 114 | /\ serverState = "running" 115 | /\ [type |-> "Broadcast", party |-> p, round |-> r] \notin msgs 116 | /\ msgs' = msgs \cup {[type |-> "Broadcast", party |-> p, round |-> r]} 117 | /\ UNCHANGED <> 118 | 119 | \* The server upon receiving a reqest to broadcast will relay the message 120 | \* to all parties. Notice: the sending party might get her message as well 121 | RelayBroadcast(r,p) == 122 | /\ assignedParties = PARTIES 123 | /\ serverState = "running" 124 | /\ [type |-> "Broadcast", party |-> p, round |-> r] \in msgs 125 | /\ [type |-> "RelayBroadcast", party |-> p, round |-> r] \notin msgs 126 | /\ msgs' = msgs \cup {[type |-> "RelayBroadcast", party |-> p, round |-> r]} 127 | /\ UNCHANGED <> 128 | 129 | \* When the protocol runs each party can ask the server once every round 130 | \* to send a message to another party. Notice the receiver can also be the sender 131 | ReqToP2P(r,p1,p2) == 132 | /\ assignedParties = PARTIES 133 | /\ serverState = "running" 134 | /\ [type |-> "P2P", from |-> p1, to |-> p2, round |-> r] \notin msgs 135 | /\ msgs' = msgs \cup {[type |-> "P2P",from |-> p1, to |-> p2, round |-> r]} 136 | /\ UNCHANGED <> 137 | 138 | \* The server will relay p2p messages 139 | RelayP2P(r,p1,p2) == 140 | /\ assignedParties = PARTIES 141 | /\ serverState = "running" 142 | /\ [type |-> "P2P",from |-> p1, to |-> p2, round |-> r] \in msgs 143 | /\ [type |-> "RelayP2P",from |-> p1, to |-> p2, round |-> r] \notin msgs 144 | /\ msgs' = msgs \cup {[type |-> "RelayP2P", from |-> p1, to |-> p2, round |-> r]} 145 | /\ UNCHANGED <> 146 | 147 | 148 | ----------------------------------------------------------------------------- 149 | Next == 150 | Start \/ Abort 151 | \/ (\E p \in PARTIES : PartyAbort(p) ) 152 | \/ (\E p \in PARTIES : PartyReady(p) ) 153 | \/ (\E p \in PARTIES : Assign(p) ) 154 | \/ (\E p \in PARTIES : \E r \in ROUNDS : ReqToBroadcast(r,p)) 155 | \/ (\E p \in PARTIES : \E r \in ROUNDS : RelayBroadcast(r,p) ) 156 | \/ (\E p1 \in PARTIES : \E p2 \in PARTIES : \E r \in ROUNDS : ReqToP2P(r,p1,p2)) 157 | \/ (\E p1 \in PARTIES : \E p2 \in PARTIES : \E r \in ROUNDS : RelayP2P(r,p1,p2)) 158 | 159 | Spec == Init /\ [][Next]_<> 160 | THEOREM Spec => []TypeOK 161 | ============================================================================= 162 | \* Modification History 163 | \* Last modified Mon Dec 10 21:24:30 IST 2018 by omershlo 164 | \* Created Mon Dec 10 21:18:59 IST 2018 by omershlo 165 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/Formal-spec/coq/Makefile: -------------------------------------------------------------------------------- 1 | 2 | COQC = coqc 3 | COQDOC = coqdoc 4 | 5 | LIB = subset 6 | SOURCE = relayserver 7 | 8 | compile: $(LIB).vo $(SOURCE).vo 9 | 10 | doc: $(SOURCE).vo $(SOURCE).pdf 11 | 12 | 13 | %.vo: %.v 14 | $(COQC) $< 15 | 16 | $(SOURCE).pdf: $(SOURCE).v $(SOURCE).vo 17 | $(COQDOC) --pdf --utf8 --parse-comments -t "Kzen : $(SOURCE)" $< -o $@ 18 | 19 | clean: 20 | rm -f *~ 21 | rm -f $(SOURCE).vo 22 | rm -f $(SOURCE).glob 23 | rm -f $(LIB).vo 24 | rm -f $(LIB).glob 25 | 26 | cleanall: clean 27 | rm -f $(SOURCE).pdf 28 | 29 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/Formal-spec/coq/README.md: -------------------------------------------------------------------------------- 1 | 2 | COQ formalization of the relay server 3 | ===================================== 4 | 5 | **Author**: Frederic Peschanski - LIP6 - Sorbonne University 6 | 7 | To compile the required library and check the development: 8 | 9 | ``` 10 | $ make 11 | ``` 12 | 13 | To generate the pdf: 14 | 15 | ``` 16 | $ make doc 17 | ``` 18 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/Formal-spec/coq/relayserver.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZenGo-X/white-city/eada16e95964fbaf23ca86e2251789bfa6e57bfd/RelayProofsOfConcept/Formal-spec/coq/relayserver.pdf -------------------------------------------------------------------------------- /RelayProofsOfConcept/Formal-spec/coq/relayserver.v: -------------------------------------------------------------------------------- 1 | 2 | 3 | (** 4 | 5 | _Author_ : Frederic Peschanski -- LIP6 -- Sorbonne University 6 | 7 | * Introduction 8 | 9 | 10 | This is a (for now) partial "port" of TLA+ relayserver example 11 | in Coq... It is not to say that "we should use coq" but it 12 | is the tool I am most familiar with, and my idea is to 13 | see if the limitation you encounter with TLA+ can be 14 | lifted using Coq... For now I am trying to find a proper 15 | way to model the same thing, overally... 16 | *) 17 | 18 | (** 19 | 20 | You are constructing a state-machine, and the formal method 21 | I am most familiar with when it comes to state machines is 22 | Event-B ... However I don't want to use Event-B because like 23 | TLA+ it is untyped, it has strong expressivity limitations, etc. 24 | I have already implemented the main ideas of Event-B, this is 25 | my inspiration for formulating the TLA+ spec in Coq. 26 | 27 | *) 28 | 29 | (** 30 | In Coq there is no methodological support. It is very difficult to find limitations 31 | in terms of expressivity (you have all mathematics reachable with type theory) 32 | but then you lose the underlying methodology 33 | and many automation tools (but Coq has also support for automation, cf. the one liner 34 | "firstorder" proofs below). 35 | 36 | In a way Coq is a general purpose "specification language" 37 | (like general purpose programming language) whereas TLA+ (and EventB) 38 | are domain-specific languages (something like SQL ? ;-) 39 | *) 40 | 41 | (** 42 | 43 | * Basic definitions 44 | 45 | *) 46 | 47 | Require Import Nat. (* use Nat for rounds ? *) 48 | Require Import subset. 49 | 50 | (** These are just basic enumerations (sum types) *) 51 | 52 | Inductive ServerState : Set := 53 | | init : ServerState 54 | | running : ServerState. 55 | 56 | Inductive PartyState : Set := 57 | | idle : PartyState 58 | | ready : PartyState 59 | | assigned : PartyState 60 | | aborted : PartyState. 61 | 62 | (** The following is not really needed but then a party record has something in it *) 63 | 64 | Variable IDENT : Set. 65 | 66 | Record Party : Set := 67 | mkParty { 68 | id : IDENT; 69 | state : PartyState 70 | }. 71 | 72 | Definition changePartyState (p : Party) (st : PartyState) := 73 | mkParty p.(id) st. 74 | 75 | (** Message contents can be formalized, I used 76 | nats for the rounds but a dedicated type can 77 | be defined if required *) 78 | 79 | Definition ROUND := nat. 80 | 81 | Inductive Message : Set := 82 | abort | start : Message 83 | | readyMsg : Party -> Message 84 | | assign : Party -> Message 85 | | abortReq : Party -> Message 86 | | P2P : Party -> Party -> ROUND -> Message 87 | | relayP2P : Party -> Party -> ROUND -> Message 88 | | broadcast : Party -> ROUND -> Message 89 | | relayBroadcast : Party -> ROUND -> Message. 90 | 91 | (** 92 | Modeling sets in type theory and Coq is not trivial, 93 | here I use the "Subtype" approach which defines 94 | a set as a function from a type to propositions, 95 | i.e. for a set S of elements of type T a value 96 | e of type T is element of S iff (S e) holds. 97 | 98 | This is typed set theory (better than set theory IMHO ;-) 99 | 100 | If we really want to model finite sets (e.g. to 101 | reason on cardinality) then we must proceed differently... 102 | 103 | I wrote a minimal set library to support this, it is very 104 | easy to understand (cf. subset.v in the archive). 105 | 106 | The following in the main definition of the system state. 107 | 108 | *) 109 | 110 | Record System : Type := 111 | mkSys { 112 | parties : SET Party; 113 | serverState : ServerState; 114 | network : SET Message; 115 | }. 116 | 117 | (** Remark: the system record has no invariant, but it is 118 | a common (and encouraged) practice to define the constraint 119 | such that the entity is consistent. 120 | 121 | Suggestion : we should discuss invariant(s) ;-). 122 | *) 123 | 124 | 125 | (** 126 | 127 | * Init Event 128 | 129 | In the EventB terminology the description of a possible transition 130 | in the state machine is an "event"... It is defined by preconditions (or guards, there 131 | is a distinction if we are interested in refinement) and 132 | the event itself... Sometimes events are non-deterministic but this is not the case 133 | in this development (this is a good thing). 134 | *) 135 | 136 | Definition InitPartyPrecond (p : Party) := 137 | p.(state) = idle. 138 | 139 | Definition InitSysPrecond (parties : Party -> Prop) := 140 | forall p : Party, p ∈ parties -> InitPartyPrecond p. 141 | 142 | (** 143 | Here we can define "the" initial state of the system 144 | in a deterministic way (i.e. as a function). This 145 | is often called an action on the pre-state. 146 | 147 | We could just define a postcondition relating the 148 | pre-state with the post-state (cf. below) 149 | *) 150 | 151 | Definition InitSysEvent (parties : Party -> Prop) := 152 | mkSys parties init ∅. 153 | 154 | (** An example lemma. 155 | 156 | Assuming the precondition, all the parties in the 157 | initialized system are idle 158 | 159 | It's obvious and Coq knows it 160 | so the "auto" tactic works perfectly... This kind 161 | of easy lemma can be useful in further proofs... *) 162 | Lemma InitSys_all_parties_idle: 163 | forall ps : SET Party, 164 | InitSysPrecond ps 165 | -> let sys := InitSysEvent ps 166 | in 167 | forall p : Party, p ∈ (sys.(parties)) -> p.(state) = idle. 168 | Proof. 169 | auto. 170 | Qed. 171 | 172 | Lemma InitSys_no_message: 173 | forall ps : SET Party, 174 | forall m : Message, m ∉ ((InitSysEvent ps).(network)). 175 | Proof. 176 | auto. 177 | Qed. 178 | 179 | (** 180 | * PartyReady event 181 | *) 182 | 183 | Definition PartyReadyPrecond (s : System) (p : Party):= 184 | s.(serverState) = init 185 | /\ p ∈ (s.(parties)) 186 | /\ p.(state) <> ready. 187 | 188 | Definition setPartyState (parties : SET Party) (p : Party) (st : PartyState) := 189 | swap p (changePartyState p st) parties. 190 | 191 | 192 | (* This covers many UNCHANGED constraints *) 193 | Lemma UnchangedOtherParties: 194 | forall parties : SET Party, forall p p' : Party, forall st : PartyState, 195 | p' <> p -> p' ∈ parties -> p' ∈ (setPartyState parties p st). 196 | Proof. 197 | firstorder. 198 | Qed. 199 | 200 | Definition PartyReadyEvent (s : System) (p : Party) := 201 | mkSys (setPartyState s.(parties) p ready) 202 | init 203 | ((readyMsg p) # (s.(network))). 204 | 205 | 206 | (* This is an examples of an UNCHANGED requireent 207 | and it is not an axiom, it is a proof *) 208 | Lemma partyReadyOtherParties: 209 | forall sys : System, forall p : Party, 210 | PartyReadyPrecond sys p 211 | -> let sys' := PartyReadyEvent sys p 212 | in forall p' : Party, 213 | p' ∈ (sys.(parties)) 214 | -> p' <> p 215 | -> p' ∈ (sys'.(parties)). 216 | Proof. 217 | firstorder. (* one liner ! *) 218 | Qed. 219 | 220 | 221 | (** * Assign event 222 | *) 223 | 224 | Definition AssignPrecond (sys : System) (p : Party) := 225 | sys.(serverState) = init 226 | /\ p ∈ (sys.(parties)) 227 | /\ (readyMsg p) ∈ (sys.(network)) (* Question: this message is not consumed ? *) 228 | /\ (assign p) ∉ (sys.(network)). 229 | 230 | Definition AssignEvent (sys : System) (p : Party) := 231 | mkSys (setPartyState sys.(parties) p assigned) 232 | init 233 | ((assign p) # (sys.(network))). 234 | 235 | (** * Start event 236 | *) 237 | 238 | Definition StartPrecond (sys : System) := 239 | sys.(serverState) = init 240 | /\ forall p : Party, p ∈ (sys.(parties)) -> p.(state) = assigned. 241 | 242 | Definition StartEvent (sys : System) := 243 | mkSys (sys.(parties)) 244 | running 245 | (start # (sys.(network))). 246 | 247 | (** * PartyAbort event 248 | *) 249 | 250 | Definition PartyAbortPrecond (sys : System) (p : Party) := 251 | sys.(serverState) = running 252 | /\ p ∈ (sys.(parties)) 253 | /\ p.(state) = assigned 254 | /\ (abortReq p) ∈ (sys.(network)). 255 | 256 | Definition PartyAbortEvent (sys : System) (p : Party) := 257 | mkSys (setPartyState sys.(parties) p aborted) 258 | init 259 | { abort }. 260 | 261 | (** * Abort event 262 | *) 263 | 264 | Definition AbortPrecond (sys : System) := 265 | sys.(serverState) = init 266 | /\ abort ∈ (sys.(network)). 267 | 268 | Definition AbortEvent (sys : System) := 269 | mkSys ∅ init ∅. 270 | 271 | (** * Event ReqToBroadcast *) 272 | 273 | Definition ReqToBroadcastPrecond (sys : System) (p : Party) (r : ROUND) := 274 | sys.(serverState) = running 275 | /\ p ∈ (sys.(parties)) 276 | /\ (forall p : Party, p.(state) = assigned) 277 | /\ (broadcast p r) ∉ (sys.(network)). 278 | 279 | Definition ReqToBroadcastEvent (sys : System) (p : Party) (r : ROUND) := 280 | mkSys (sys.(parties)) (sys.(serverState)) 281 | ((broadcast p r) # (sys.(network))). 282 | 283 | (** * Event RelayBroadcast *) 284 | 285 | Definition RelayBroadcastPrecond (sys : System) (p : Party) (r : ROUND) := 286 | sys.(serverState) = running 287 | /\ p ∈ (sys.(parties)) 288 | /\ (forall p : Party, p.(state) = assigned) 289 | /\ (broadcast p r) ∈ (sys.(network)) 290 | /\ (relayBroadcast p r) ∉ (sys.(network)). 291 | 292 | Definition RelayBroadcastEvent (sys : System) (p : Party) (r : ROUND) := 293 | mkSys (sys.(parties)) (sys.(serverState)) 294 | ((relayBroadcast p r) # (sys.(network))). 295 | 296 | (** * Event ReqToP2P *) 297 | 298 | Definition ReqToP2PPrecond (sys : System) (p1 p2 : Party) (r : ROUND) := 299 | sys.(serverState) = running 300 | /\ p1 ∈ (sys.(parties)) 301 | /\ p2 ∈ (sys.(parties)) 302 | /\ (forall p : Party, p.(state) = assigned) 303 | /\ (P2P p1 p2 r) ∉ (sys.(network)). 304 | 305 | Definition ReqToP2PEvent (sys : System) (p1 p2 : Party) (r : ROUND) := 306 | mkSys (sys.(parties)) (sys.(serverState)) 307 | ((P2P p1 p2 r) # (sys.(network))). 308 | 309 | 310 | (** * Event RelayP2P *) 311 | 312 | Definition RelayP2PPrecond (sys : System) (p1 p2 : Party) (r : ROUND) := 313 | sys.(serverState) = running 314 | /\ p1 ∈ (sys.(parties)) 315 | /\ p2 ∈ (sys.(parties)) 316 | /\ (forall p : Party, p.(state) = assigned) 317 | /\ (P2P p1 p2 r) ∈ (sys.(network)) 318 | /\ (relayP2P p1 p2 r) ∉ (sys.(network)). 319 | 320 | Definition RelayP2PEvent (sys : System) (p1 p2 : Party) (r : ROUND) := 321 | mkSys (sys.(parties)) (sys.(serverState)) 322 | ((relayP2P p1 p2 r) # (sys.(network))). 323 | 324 | 325 | (* * Transition system 326 | *) 327 | 328 | (** Transitions (of state machines) are what appear to me 329 | the closest the next operator of TLA+ *) 330 | 331 | Inductive Trans (sys : System) : System -> Prop := 332 | | start_t: StartPrecond sys -> Trans sys (StartEvent sys) 333 | | abort_t: AbortPrecond sys -> Trans sys (AbortEvent sys) 334 | | party_abort_t: forall p : Party, 335 | PartyAbortPrecond sys p -> Trans sys (PartyAbortEvent sys p) 336 | | party_ready_t: forall p : Party, 337 | PartyReadyPrecond sys p -> Trans sys (PartyReadyEvent sys p) 338 | | assign_t: forall p : Party, 339 | AssignPrecond sys p -> Trans sys (AssignEvent sys p) 340 | | req_broadcast_t: forall p : Party, forall r : ROUND, 341 | ReqToBroadcastPrecond sys p r -> Trans sys (ReqToBroadcastEvent sys p r) 342 | | relay_broadcast_t: forall p : Party, forall r : ROUND, 343 | RelayBroadcastPrecond sys p r -> Trans sys (RelayBroadcastEvent sys p r) 344 | | req_p2p_t: forall p1 p2 : Party, forall r : ROUND, 345 | ReqToP2PPrecond sys p1 p2 r -> Trans sys (ReqToP2PEvent sys p1 p2 r) 346 | | relay_p2p_t: forall p1 p2 : Party, forall r : ROUND, 347 | RelayP2PPrecond sys p1 p2 r -> Trans sys (RelayP2PEvent sys p1 p2 r). 348 | 349 | 350 | (** The "always", or invariant, predicate can be modeled as a 351 | kind of transitive closure of transitions. *) 352 | 353 | Inductive Behavior : System -> Prop := 354 | | beh_init: forall parties : SET Party, 355 | InitSysPrecond parties -> Behavior (InitSysEvent parties) 356 | | beh_trans: forall sys sys' : System, 357 | Behavior sys -> Trans sys sys' -> Behavior sys'. 358 | 359 | (** 360 | 361 | The next question is : what it is that we want to prove ? 362 | It is useless to prove any type constraints because we are 363 | in type theory and everything is typed by construction. 364 | 365 | That's all for now ... I'll continue and then discuss withyou 366 | (Omer) the issues you raised. 367 | 368 | *) 369 | 370 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/Formal-spec/coq/subset.v: -------------------------------------------------------------------------------- 1 | 2 | 3 | Require Import Setoid. 4 | 5 | Definition SET (T : Type):= T -> Prop. 6 | 7 | Bind Scope subset_scope with SET. 8 | 9 | Definition elem {T : Type} (e : T) (S : SET T) := 10 | S e. 11 | 12 | Notation "e ∈ S" := (elem e S) (at level 0). 13 | Notation "e ∉ S" := (not (elem e S)) (at level 0). 14 | 15 | 16 | Theorem elem_not_elem: 17 | forall T : Type, forall a b : T, forall S : SET T, 18 | a ∈ S -> b ∉ S -> a <> b. 19 | Proof. 20 | intros. 21 | unfold elem in *. 22 | intro Hcontra. 23 | rewrite <- Hcontra in H0. 24 | contradiction. 25 | Qed. 26 | 27 | Theorem elem_classic: 28 | forall T : Type, forall e : T, forall S : SET T, 29 | e ∈ S -> e ∉ S -> False. 30 | Proof. 31 | intros. 32 | assert (Hcontra: e <> e). 33 | { apply elem_not_elem with (S:=S) ; assumption. } 34 | apply Hcontra. 35 | reflexivity. 36 | Qed. 37 | 38 | Definition Emptyset {T : Type} := 39 | fun (_ : T) => False. 40 | 41 | Notation "∅" := Emptyset. 42 | 43 | Lemma Emptyset_notIn: 44 | forall T : Type, forall e : T, 45 | e ∉ ∅. 46 | Proof. 47 | auto. 48 | Qed. 49 | 50 | Hint Resolve Emptyset_notIn. 51 | 52 | (* This is an encoding of S' = S ∪ {e} *) 53 | Definition add {T : Type} (e : T) (S : SET T) := 54 | fun e' : T => e' = e \/ (e' ∈ S). 55 | 56 | Notation "e # s" := (add e s) (at level 60, right associativity). 57 | 58 | Theorem add_in: 59 | forall T : Type, forall e : T, forall S : SET T, e ∈ (e # S). 60 | Proof. 61 | intros. left. reflexivity. 62 | Qed. 63 | 64 | Hint Resolve add_in. 65 | 66 | Theorem add_sup: 67 | forall T : Set, forall a b : T, forall S : SET T, 68 | a ∈ S -> a ∈ (b # S). 69 | Proof. 70 | intros. right. trivial. 71 | Qed. 72 | 73 | Hint Resolve add_sup. 74 | 75 | Definition seteq {T : Type} (S1 : SET T) (S2 : SET T) : Prop := 76 | forall x : T, x ∈ S1 <-> x ∈ S2. 77 | 78 | Notation "S1 ~ S2" := (seteq S1 S2) (at level 70, no associativity). 79 | 80 | Theorem add_idem: 81 | forall T : Set, forall e : T, forall S : T -> Prop, 82 | e ∈ S -> e # S ~ S. 83 | Proof. 84 | intros T e S Hin. 85 | split. 86 | - intro H1. 87 | destruct H1 as [H1 | H2]. 88 | + subst. 89 | assumption. 90 | + assumption. 91 | - intro H1. 92 | apply add_sup. 93 | assumption. 94 | Qed. 95 | 96 | Notation "{ e }" := (e # ∅). 97 | 98 | 99 | Definition remove {T : Set} (e : T) (S : SET T) := 100 | fun e' : T => e' ∈ S /\ e' <> e. 101 | 102 | Lemma remove_notin: 103 | forall T : Set, forall e : T, forall S : SET T, 104 | e ∉ (remove e S). 105 | Proof. 106 | intros. 107 | unfold not. unfold remove. 108 | intros. 109 | inversion H. 110 | contradiction. 111 | Qed. 112 | 113 | Hint Resolve remove_notin. 114 | 115 | Lemma remove_others: 116 | forall T : Set, forall a b : T, forall S : SET T, 117 | a ∈ S -> a <> b -> a ∈ (remove b S). 118 | Proof. 119 | intros. 120 | split ; assumption. 121 | Qed. 122 | 123 | Hint Resolve remove_others. 124 | 125 | Lemma remove_elim: 126 | forall T : Set, forall e : T, forall S : SET T, 127 | e ∉ S -> remove e S ~ S. 128 | Proof. 129 | intros. 130 | split. 131 | - intro H1. 132 | inversion H1. 133 | assumption. 134 | - intro H2. 135 | firstorder. 136 | unfold remove. 137 | unfold elem. 138 | apply elem_not_elem with (S:=S) ; assumption. 139 | Qed. 140 | 141 | Definition swap {T : Set} (e e' : T) (S : SET T) := 142 | e' # (remove e S). 143 | 144 | Lemma swap_in: 145 | forall T : Set, forall e e': T, forall S : SET T, 146 | e ∈ (swap e' e S). 147 | Proof. 148 | intros. 149 | unfold swap. 150 | apply add_in. 151 | Qed. 152 | 153 | Theorem swap_idem: (* only with decidable equality ? *) 154 | forall T : Set, forall T_eqdec : forall a b : T, {a=b} + {a<>b}, 155 | forall e : T, forall S : SET T, 156 | e ∈ S -> (swap e e S ~ S). 157 | Proof. 158 | intros. 159 | split. 160 | - intro H1. 161 | inversion H1. 162 | subst. 163 | assumption. 164 | inversion H0. 165 | assumption. 166 | - intro H2. 167 | unfold swap. 168 | unfold remove. 169 | unfold add. 170 | unfold elem. 171 | firstorder. 172 | Qed. 173 | 174 | Theorem swap_diff: 175 | forall T : Set, forall e : T, forall S : SET T, 176 | e ∉ S -> (swap e e S ~ e # S). 177 | Proof. 178 | intros. 179 | split. 180 | - intro H1. 181 | inversion H1. 182 | + rewrite H0. 183 | auto. 184 | + inversion H0. 185 | apply add_sup. 186 | assumption. 187 | - intro H2. 188 | unfold swap. 189 | unfold add. 190 | unfold remove. 191 | unfold elem. 192 | inversion H2. 193 | + left. assumption. 194 | + right. 195 | split. 196 | * assumption. 197 | * apply elem_not_elem with (S:=S) ; assumption. 198 | Qed. 199 | 200 | -------------------------------------------------------------------------------- /RelayProofsOfConcept/README.md: -------------------------------------------------------------------------------- 1 | ## Implementations 2 | - **[Tendermint](https://github.com/KZen-networks/white-city/tree/master/RelayProofsOfConcept/EddsaTendermintServer):** Broadcast channel using Tendermint as an immutable bulletin board. 3 | - **[TokioServer](https://github.com/KZen-networks/white-city/tree/master/RelayProofsOfConcept/EddsaTokioServer):** A socket level implementation using Tokio Crate. 4 | - **[RocketServer](https://github.com/KZen-networks/white-city/tree/master/RelayProofsOfConcept/EddsaRocketServer):** An Http server implementation using Rocket crate. 5 | - **[Formal-spec](https://github.com/KZen-networks/white-city/tree/master/RelayProofsOfConcept/Formal-spec)** Formal verification of the state machine model in Coq/TLA+ 6 | -------------------------------------------------------------------------------- /White-City-Report/white_city.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZenGo-X/white-city/eada16e95964fbaf23ca86e2251789bfa6e57bfd/White-City-Report/white_city.pdf -------------------------------------------------------------------------------- /White-City-Report/whitecity_new.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZenGo-X/white-city/eada16e95964fbaf23ca86e2251789bfa6e57bfd/White-City-Report/whitecity_new.pdf --------------------------------------------------------------------------------