1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
//! # Example Usage of the `oblivc` crate //! This crate uses the [`oblivc`][1] crate to solve [Yao's Millionaire's Problem][2]. //! We implement our solution in Obliv-C as a function [`millionaire`][3] that reads both parties' //! inputs, compares them, and sets the output to -1, 0, or 1 if party 1's input was less than, //! equal to, or greater than party 2's. //! //! ## Compilation //! First, in [`build.rs`][4], we compile [`millionaire.oc`][5] using the Obliv-C compiler. //! This also tells Cargo to link the resulting objects after compiling our rust source code. //! //! ```no_run //! # extern crate oblivc; //! oblivc::compiler() //! .file("src/millionaire.oc") //! .include("src") //! .compile("millionaire"); //! ``` //! //! Next, we generate Rust bindings for both the `millionaire` function and the `millionaire_args` //! struct defined in [`millionaire.h`][6]. //! //! ``` //! # let out_dir = std::path::PathBuf::from(env!("OUT_DIR")); //! # extern crate oblivc; //! oblivc::bindings() //! .header("src/millionaire.h") //! .generate().unwrap() //! .write_to_file(out_dir.join("millionaire.rs")).unwrap(); //! ``` //! Note that for small projects, these bindings can also be generated by hand. Using `bindgen` //! is just more convenient. //! //! ## Calling Obliv-C from Rust //! In our Rust source files, we first include the bindings generated by the build script. //! //! ``` //! include!(concat!(env!("OUT_DIR"), "/millionaire.rs")); //! # fn main() {} //! ``` //! //! Now, for each party, we set up a [`millionaire_args`][7] struct, as well as a //! [`ProtocolDesc`][8] describing our protocol. In this example, we let party 1 accept a TCP //! connection using Obliv-C's native sockets. //! //! ``` //! # extern crate oblivc; //! # include!(concat!(env!("OUT_DIR"), "/millionaire.rs")); //! # use std::thread; //! # fn main() { //! # let server = std::thread::spawn(|| { //! let mut args = millionaire_args { //! input: 10, //! output: 0, //! }; //! let pd = oblivc::protocol_desc() //! .party(1) //! .accept("56734").unwrap(); //! # unsafe { pd.exec_yao_protocol(millionaire, &mut args); } //! # }); //! # let mut args = millionaire_args { //! # input: 20, //! # output: 0, //! # }; //! # let pd = oblivc::protocol_desc() //! # .party(2) //! # .connect("localhost", "56734").unwrap(); //! # unsafe { pd.exec_yao_protocol(millionaire, &mut args); } //! # server.join().unwrap(); //! # assert!(args.output == -1); //! # } //! ``` //! //! Party 2 can then connect to the specified address: //! //! ``` //! # extern crate oblivc; //! # include!(concat!(env!("OUT_DIR"), "/millionaire.rs")); //! # fn main() { //! # let server = std::thread::spawn(|| { //! # let mut args = millionaire_args { //! # input: 10, //! # output: 0, //! # }; //! # let pd = oblivc::protocol_desc() //! # .party(1) //! # .accept("67845").unwrap(); //! # unsafe { pd.exec_yao_protocol(millionaire, &mut args); } //! # }); //! let mut args = millionaire_args { //! input: 20, //! output: 0, //! }; //! let pd = oblivc::protocol_desc() //! .party(2) //! .connect("localhost", "67845").unwrap(); //! # unsafe { pd.exec_yao_protocol(millionaire, &mut args); } //! # server.join().unwrap(); //! # assert!(args.output == -1); //! # } //! ``` //! //! To execute the protocol, both parties call //! //! ``` //! # extern crate oblivc; //! # include!(concat!(env!("OUT_DIR"), "/millionaire.rs")); //! # fn main() { //! # let server = std::thread::spawn(|| { //! # let mut args = millionaire_args { //! # input: 10, //! # output: 0, //! # }; //! # let pd = oblivc::protocol_desc() //! # .party(1) //! # .accept("78956").unwrap(); //! # unsafe { pd.exec_yao_protocol(millionaire, &mut args); } //! # }); //! # let mut args = millionaire_args { //! # input: 20, //! # output: 0, //! # }; //! # let pd = oblivc::protocol_desc() //! # .party(2) //! # .connect("localhost", "78956").unwrap(); //! unsafe { pd.exec_yao_protocol(millionaire, &mut args); } //! # server.join().unwrap(); //! # assert!(args.output == -1); //! # } //! ``` //! //! Note that this function call is `unsafe`, since there's no guarantee about the safety of the //! Obliv-C source code we wrote. It is up to the user of the `oblivc` crate to ensure their calls //! to [`exec_yao_protocol`][9] are safe. //! //! ## Other Transports //! Besides native sockets from Obliv-C's interface, any objects that implement [`Read`][10] and //! [`Write`][11] can be used as transport for the protocol execution. //! Examples using Rust's [`TcpStream`][12]s and [`UnixStream`][13]s can be found in the //! [`tests`][14] folder. //! //! [1]: ../oblivc/index.html //! [2]: https://en.wikipedia.org/wiki/Yao%27s_Millionaires%27_Problem //! [3]: https://github.com/schoppmp/oblivc-rust/blob/master/test-oblivc/src/millionaire.oc#L4 //! [4]: https://github.com/schoppmp/oblivc-rust/blob/master/test-oblivc/build.rs //! [5]: https://github.com/schoppmp/oblivc-rust/blob/master/test-oblivc/src/millionaire.oc //! [6]: https://github.com/schoppmp/oblivc-rust/blob/master/test-oblivc/src/millionaire.h //! [7]: struct.millionaire_args.html //! [8]: ../oblivc/struct.ProtocolDesc.html //! [9]: ../oblivc/struct.ProtocolDesc.html#method.exec_yao_protocol //! [10]: https://doc.rust-lang.org/nightly/std/io/trait.Read.html //! [11]: https://doc.rust-lang.org/nightly/std/io/trait.Write.html //! [12]: https://doc.rust-lang.org/std/net/struct.TcpStream.html //! [13]: https://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html //! [14]: https://github.com/schoppmp/oblivc-rust/tree/master/test-oblivc/tests #![doc(html_root_url = "https://schoppmp.github.io/doc/oblivc-rust/")] extern crate oblivc; include!(concat!(env!("OUT_DIR"), "/millionaire.rs")); #[cfg(test)] mod tests { use super::*; #[test] #[should_panic] fn test_no_party() { let mut args = millionaire_args { input: 0, output: 0, }; let pd = oblivc::protocol_desc(); unsafe { pd.exec_yao_protocol(millionaire, &mut args); } } #[test] #[should_panic] fn test_no_trans() { let mut args = millionaire_args { input: 0, output: 0, }; let pd = oblivc::protocol_desc().party(1); unsafe { pd.exec_yao_protocol(millionaire, &mut args); } } }