use mpstthree::binary::struct_trait::{end::End, recv::Recv, send::Send, session::Session}; use mpstthree::role::broadcast::RoleBroadcast; use mpstthree::role::end::RoleEnd; use mpstthree::{checker_concat, checker_concat_impl, generate}; use rand::{thread_rng, Rng}; use std::error::Error; use std::fs::read_to_string; // See the folder scribble_protocols for the related Scribble protocol generate!("recursive", MeshedChannels, A, C, S); // Payloads struct Start; struct Redirect; struct Login; struct Auth; struct Password; struct Success; struct Token; struct Fail; struct Received; // Types // A type Choose0fromAtoC = ::Dual; type Choose0fromAtoS = ::Dual; // C enum Branching0fromAtoC { Success( MeshedChannels< Recv, Send>, RoleA>>, NameC, >, ), Fail( MeshedChannels< Recv, Send>, RoleA>>, NameC, >, ), } type Offer0fromCtoA = Recv; // S enum Branching0fromAtoS { Success( MeshedChannels< Send>, Recv>, RoleC>>>, NameS, >, ), Fail(MeshedChannels>, RoleC>, NameS>), } type Offer0fromStoA = Recv; // Creating the MP sessions // A type EndpointASuccess = MeshedChannels< Send, Recv>, RoleC>>, NameA, >; type EndpointAFail = MeshedChannels, End, RoleC, NameA>; type EndpointA = MeshedChannels< Recv>>, Choose0fromAtoS, RoleC>>, NameA, >; // C type EndpointC = MeshedChannels< Send>>, Send>, RoleS>>>>>, NameC, >; // S type EndpointS = MeshedChannels< Offer0fromStoA, Recv>, RoleC>>, NameS, >; // Functions fn endpoint_a(s: EndpointA) -> Result<(), Box> { let (_, s) = s.recv(); let s = s.send(Auth {}); let (_, s) = s.recv(); let expected: i32 = thread_rng().gen_range(1..=3); if 1 == expected { let s: EndpointASuccess = choose_mpst_a_to_all!(s, Branching0fromAtoC::Success, Branching0fromAtoS::Success); let s = s.send(Success {}); let (_, s) = s.recv(); let s = s.send(Token {}); s.close() } else { let s: EndpointAFail = choose_mpst_a_to_all!(s, Branching0fromAtoC::Fail, Branching0fromAtoS::Fail); let s = s.send(Fail {}); s.close() } } fn endpoint_c(s: EndpointC) -> Result<(), Box> { let s = s.send(Start {}); let (_, s) = s.recv(); let s = s.send(Login {}); let (_, s) = s.recv(); let s = s.send(Password {}); offer_mpst!(s, { Branching0fromAtoC::Success(s) => { let (_, s) = s.recv(); let s = s.send(Success { }); let (_, s) = s.recv(); s.close() }, Branching0fromAtoC::Fail(s) => { let (_, s) = s.recv(); let s = s.send(Fail { }); let (_, s) = s.recv(); s.close() }, }) } fn endpoint_s(s: EndpointS) -> Result<(), Box> { let (_, s) = s.recv(); let s = s.send(Redirect {}); offer_mpst!(s, { Branching0fromAtoS::Success(s) => { let (_, s) = s.recv(); let s = s.send(Token { }); let (_, s) = s.recv(); let s = s.send(Token { }); s.close() }, Branching0fromAtoS::Fail(s) => { let (_, s) = s.recv(); let s = s.send(Received { }); s.close() }, }) } fn main() { checking(); let (thread_a, thread_c, thread_s) = fork_mpst(endpoint_a, endpoint_c, endpoint_s); thread_a.join().unwrap(); thread_c.join().unwrap(); thread_s.join().unwrap(); } checker_concat_impl!( [Branching0fromAtoC, Success, Branching0fromAtoS, Success,], [Branching0fromAtoC, Fail, Branching0fromAtoS, Fail,] ); // Check for bottom-up approach fn checking() { let _ = checker_concat!( "o_auth_checking", EndpointA, EndpointC, EndpointS => [ EndpointASuccess, Branching0fromAtoC, Success, Branching0fromAtoS, Success, ], [ EndpointAFail, Branching0fromAtoC, Fail, Branching0fromAtoS, Fail, ] ) .unwrap(); assert_eq!( "CSA: \u{1b}[92mTrue\n\ \u{1b}[0mBasic: \u{1b}[92mTrue\n\ \u{1b}[0mreduced 1-exhaustive: \u{1b}[92mTrue\n\ \u{1b}[0mreduced 1-safe: \u{1b}[92mTrue\n\ \u{1b}[0m\n", read_to_string("outputs/o_auth_checking_1_kmc.txt").unwrap() ); }