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