1RAPPOR C++ Client 2================= 3 4We provide both a low level and high level client API. The low level API 5implements just the RAPPOR encoding algorithm on strings, with few 6dependencies. 7 8The high level API provides wrappers that bundle encoded values into Protocol 9Buffer messages. 10 11Build Instructions 12------------------ 13 14You'll need a C++ compiler, the protobuf compiler, and a library that 15implements common hash functions (e.g. OpenSSL). 16 17On Ubuntu or Debian, the protobuf compiler and header files can be installed 18with: 19 20 sudo apt-get install protobuf-compiler libprotobuf-dev 21 22OpenSSL can be installed with: 23 24 sudo apt-get install libssl-dev 25 26Test 27---- 28 29After installing dependencies, You can test it out easily on your machine: 30 31 ./demo.sh quick-cpp 32 33This builds the test harness using a Makefile, and then runs the regtest.sh 34simulation. The last few lines of output will look like this: 35 36 Done running all test instances 37 Instances succeeded: 1 failed: 0 running: 0 total: 1 38 Wrote _tmp/cpp/results.html 39 URL: file:///usr/local/google/home/andychu/git/rappor/_tmp/cpp/results.html 40 41Open the HTML file to see a plot and stats. 42 43 44Encoder 45------- 46 47The low level API is `Encoder`. You instantiatate it with RAPPOR encoding 48parameters and application dependencies. It has a method `EncodeString()` that 49takes an input string (no other types), sets an output parameter of type 50`rappor::Bits`, and returns success or failure. 51 52```cpp 53#include <cassert> 54 55#include "encoder.h" 56#include "openssl_hash_impl.h" 57#include "unix_kernel_rand_impl.h" 58 59int main(int argc, char** argv) { 60 FILE* fp = fopen("/dev/urandom", "r"); 61 rappor::UnixKernelRand irr_rand(fp); 62 63 rappor::Deps deps(rappor::Md5, "client-secret", rappor::HmacSha256, 64 irr_rand); 65 rappor::Params params(32, // num_bits (k) 66 2, // num_hashes (h) 67 128, // num_cohorts (m) 68 0.25, // probability f for PRR 69 0.75, // probability p for IRR 70 0.5); // probability q for IRR 71 72 const char* encoder_id = "metric-name"; 73 rappor::Encoder encoder(encoder_id, params, deps); 74 75 // Now use it to encode values. The 'out' value can be sent over the 76 // network. 77 rappor::Bits out; 78 assert(encoder.EncodeString("foo", &out)); // returns false on error 79 printf("'foo' encoded with RAPPOR: %0x, cohort %d\n", out, encoder.cohort()); 80 81 // Raw bits 82 assert(encoder.EncodeBits(0x123, &out)); // returns false on error 83 printf("0x123 encoded with RAPPOR: %0x, cohort %d\n", out, encoder.cohort()); 84} 85``` 86 87Dependencies 88------------ 89 90`rappor::Deps` is a struct-like object that holds the dependencies needed by 91the API. 92 93The application must provide the following values: 94 95- cohort: An integer between 0 and `num_cohorts - 1`. Each value is assigned 96 with equal probability to a client process. 97- client_secret: A persistent client secret (used for deterministic randomness 98 in the PRR, i.e. "memoization" requirement). 99- hash_func - string hash function implementation (e.g. MD5) 100- hmac_func - HMAC-SHA256 implementation 101- irr_rand - randomness for the IRR 102 103We provide an implementation of `hash_func` and `hmac_func` and using OpenSSL. 104If your application already has a different implementation of these functions, 105you can implement the `HashFunc` and HmacFunc` interfaces. 106 107We provide two example implementations of `irr_rand`: one based on libc 108`rand()` (insecure, for demo only), and one based on Unix `/dev/urandom`. 109 110Error Handling 111-------------- 112 113Note that incorrect usage of the `SimpleEncoder` and `Protobuf` constructors 114may cause *runtime assertions* (using `assert()`). For example, if 115Params.num\_bits is more than 32, the process will crash. 116 117Encoders should be initialized at application startup, with constant 118parameters, so this type of error should be seen early. 119 120The various `Encode()` members do *not* raise assertions. If those are used 121incorrectly, then the return value will be `false` to indicate an error. These 122failures should be handled by the application. 123 124Memory Management 125----------------- 126 127The `Encoder` instances contain pointers to `Params` and `Deps` instances, but 128don't own them. In the examples, all instances live the stack of `main()`, so 129you don't have to worry about them being destroyed. 130