xref: /aosp_15_r20/external/rappor/client/cpp/encoder_unittest.cc (revision 2abb31345f6c95944768b5222a9a5ed3fc68cc00)
1*2abb3134SXin Li #include <gtest/gtest.h>
2*2abb3134SXin Li #include <stdexcept>
3*2abb3134SXin Li 
4*2abb3134SXin Li #include "encoder.h"
5*2abb3134SXin Li #include "openssl_hash_impl.h"
6*2abb3134SXin Li #include "unix_kernel_rand_impl.h"
7*2abb3134SXin Li 
8*2abb3134SXin Li    // We need the same "random" inputs to the IRR
9*2abb3134SXin Li    // each time to have reproducible tests.
mock_urandom(void)10*2abb3134SXin Li FILE* mock_urandom(void) {
11*2abb3134SXin Li  int i;
12*2abb3134SXin Li  FILE *fp;
13*2abb3134SXin Li  fp = tmpfile();
14*2abb3134SXin Li  for (i = 0; i < 1024; i++) {
15*2abb3134SXin Li    fputc((i * 17) % 256, fp);
16*2abb3134SXin Li  }
17*2abb3134SXin Li  fflush(fp);
18*2abb3134SXin Li  fp = freopen(NULL, "r", fp);
19*2abb3134SXin Li  return fp;
20*2abb3134SXin Li }
21*2abb3134SXin Li 
22*2abb3134SXin Li class EncoderTest : public ::testing::Test {
23*2abb3134SXin Li   protected:
EncoderTest()24*2abb3134SXin Li    EncoderTest() {
25*2abb3134SXin Li       encoder_id = std::string("metric-name").c_str();
26*2abb3134SXin Li       fp = mock_urandom();
27*2abb3134SXin Li       irr_rand = new rappor::UnixKernelRand(fp);
28*2abb3134SXin Li    }
29*2abb3134SXin Li 
~EncoderTest()30*2abb3134SXin Li    virtual ~EncoderTest() {
31*2abb3134SXin Li      fclose(fp);
32*2abb3134SXin Li      delete irr_rand;
33*2abb3134SXin Li      delete deps;
34*2abb3134SXin Li      delete params;
35*2abb3134SXin Li      delete encoder;
36*2abb3134SXin Li    }
37*2abb3134SXin Li 
38*2abb3134SXin Li FILE* fp; const char* encoder_id;
39*2abb3134SXin Li    rappor::UnixKernelRand *irr_rand;
40*2abb3134SXin Li    rappor::Deps *deps;
41*2abb3134SXin Li    rappor::Params *params;
42*2abb3134SXin Li    rappor::Encoder *encoder;
43*2abb3134SXin Li    rappor::Bits bits_out;
44*2abb3134SXin Li    std::vector<uint8_t> bits_vector;
45*2abb3134SXin Li };
46*2abb3134SXin Li 
47*2abb3134SXin Li // Uses HmacSha256 and 32-bit outputs.
48*2abb3134SXin Li class EncoderUint32Test : public EncoderTest {
49*2abb3134SXin Li   protected:
EncoderUint32Test()50*2abb3134SXin Li    EncoderUint32Test() {
51*2abb3134SXin Li      deps = new rappor::Deps(rappor::Md5, "client-secret", rappor::HmacSha256,
52*2abb3134SXin Li                              *irr_rand);
53*2abb3134SXin Li      params = new rappor::Params(32,    // num_bits (k)
54*2abb3134SXin Li                                  2,     // num_hashes (h)
55*2abb3134SXin Li                                  128,   // num_cohorts (m)
56*2abb3134SXin Li                                  0.25,  // probability f for PRR
57*2abb3134SXin Li                                  0.75,  // probability p for IRR
58*2abb3134SXin Li                                  0.5);  // probability q for IRR
59*2abb3134SXin Li      encoder = new rappor::Encoder(encoder_id, *params, *deps);
60*2abb3134SXin Li    }
61*2abb3134SXin Li };
62*2abb3134SXin Li 
63*2abb3134SXin Li // Uses HmacDrbg and variable-size vector outputs.
64*2abb3134SXin Li class EncoderUnlimTest : public EncoderTest {
65*2abb3134SXin Li  protected:
EncoderUnlimTest()66*2abb3134SXin Li   EncoderUnlimTest() {
67*2abb3134SXin Li     deps = new rappor::Deps(rappor::Md5, "client-secret", rappor::HmacDrbg,
68*2abb3134SXin Li                             *irr_rand);
69*2abb3134SXin Li     params = new rappor::Params(64,    // num_bits (k)
70*2abb3134SXin Li                                 2,     // num_hashes (h)
71*2abb3134SXin Li                                 128,   // num_cohorts (m)
72*2abb3134SXin Li                                 0.25,  // probability f for PRR
73*2abb3134SXin Li                                 0.75,  // probability p for IRR
74*2abb3134SXin Li                                 0.5);  // probability q for IRR
75*2abb3134SXin Li     encoder = new rappor::Encoder(encoder_id, *params, *deps);
76*2abb3134SXin Li   }
77*2abb3134SXin Li };
78*2abb3134SXin Li 
79*2abb3134SXin Li 
80*2abb3134SXin Li ///// EncoderUint32Test
TEST_F(EncoderUint32Test,EncodeStringUint32)81*2abb3134SXin Li TEST_F(EncoderUint32Test, EncodeStringUint32) {
82*2abb3134SXin Li   ASSERT_TRUE(encoder->EncodeString("foo", &bits_out));
83*2abb3134SXin Li   ASSERT_EQ(2281639167, bits_out);
84*2abb3134SXin Li   ASSERT_EQ(3, encoder->cohort());
85*2abb3134SXin Li }
86*2abb3134SXin Li 
TEST_F(EncoderUint32Test,EncodeStringUint32Cohort)87*2abb3134SXin Li TEST_F(EncoderUint32Test, EncodeStringUint32Cohort) {
88*2abb3134SXin Li   encoder->set_cohort(4);  // Set pre-selected cohort.
89*2abb3134SXin Li   ASSERT_TRUE(encoder->EncodeString("foo", &bits_out));
90*2abb3134SXin Li   ASSERT_EQ(2281637247, bits_out);
91*2abb3134SXin Li   ASSERT_EQ(4, encoder->cohort());
92*2abb3134SXin Li }
93*2abb3134SXin Li 
TEST_F(EncoderUint32Test,EncodeBitsUint32)94*2abb3134SXin Li TEST_F(EncoderUint32Test, EncodeBitsUint32) {
95*2abb3134SXin Li   ASSERT_TRUE(encoder->EncodeBits(0x123, &bits_out));
96*2abb3134SXin Li   ASSERT_EQ(2784956095, bits_out);
97*2abb3134SXin Li   ASSERT_EQ(3, encoder->cohort());
98*2abb3134SXin Li }
99*2abb3134SXin Li 
100*2abb3134SXin Li // Negative tests
101*2abb3134SXin Li // num_bits is negative.
TEST_F(EncoderUint32Test,NumBitsMustBePositiveDeathTest)102*2abb3134SXin Li TEST_F(EncoderUint32Test, NumBitsMustBePositiveDeathTest) {
103*2abb3134SXin Li   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
104*2abb3134SXin Li   delete params;
105*2abb3134SXin Li   params = new rappor::Params(-1,    // num_bits (k) [BAD]
106*2abb3134SXin Li                               2,     // num_hashes (h)
107*2abb3134SXin Li                               128,   // num_cohorts (m)
108*2abb3134SXin Li                               0.25,  // probability f for PRR
109*2abb3134SXin Li                               0.75,  // probability p for IRR
110*2abb3134SXin Li                               0.5);  // probability q for IRR
111*2abb3134SXin Li   EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
112*2abb3134SXin Li                "Assertion.*failed");
113*2abb3134SXin Li }
114*2abb3134SXin Li 
115*2abb3134SXin Li // num_hashes is negative.
TEST_F(EncoderUint32Test,NumHashesMustBePositiveDeathTest)116*2abb3134SXin Li TEST_F(EncoderUint32Test, NumHashesMustBePositiveDeathTest) {
117*2abb3134SXin Li   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
118*2abb3134SXin Li   delete params;
119*2abb3134SXin Li   params = new rappor::Params(32,    // num_bits (k)
120*2abb3134SXin Li                               -1,    // num_hashes (h) [BAD]
121*2abb3134SXin Li                               128,   // num_cohorts (m)
122*2abb3134SXin Li                               0.25,  // probability f for PRR
123*2abb3134SXin Li                               0.75,  // probability p for IRR
124*2abb3134SXin Li                               0.5);  // probability q for IRR
125*2abb3134SXin Li   EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
126*2abb3134SXin Li                "Assertion.*failed");
127*2abb3134SXin Li }
128*2abb3134SXin Li 
129*2abb3134SXin Li // num_cohorts is negative.
TEST_F(EncoderUint32Test,NumCohortsMustBePositiveDeathTest)130*2abb3134SXin Li TEST_F(EncoderUint32Test, NumCohortsMustBePositiveDeathTest) {
131*2abb3134SXin Li   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
132*2abb3134SXin Li   delete params;
133*2abb3134SXin Li   params = new rappor::Params(32,    // num_bits (k)
134*2abb3134SXin Li                               2,     // num_hashes (h)
135*2abb3134SXin Li                               -1,   // num_cohorts (m)  [BAD]
136*2abb3134SXin Li                               0.25,  // probability f for PRR
137*2abb3134SXin Li                               0.75,  // probability p for IRR
138*2abb3134SXin Li                               0.5);  // probability q for IRR
139*2abb3134SXin Li   EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
140*2abb3134SXin Li                "Encoder.*Assertion.*failed");
141*2abb3134SXin Li }
142*2abb3134SXin Li 
143*2abb3134SXin Li // Invalid probabilities.
TEST_F(EncoderUint32Test,InvalidProbabilitiesDeathTest)144*2abb3134SXin Li TEST_F(EncoderUint32Test, InvalidProbabilitiesDeathTest) {
145*2abb3134SXin Li   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
146*2abb3134SXin Li   // prob_f negative.
147*2abb3134SXin Li   delete params;
148*2abb3134SXin Li   params = new rappor::Params(32,    // num_bits (k)
149*2abb3134SXin Li                               2,     // num_hashes (h)
150*2abb3134SXin Li                               1,   // num_cohorts (m)
151*2abb3134SXin Li                               -0.1,  // probability f for PRR [BAD]
152*2abb3134SXin Li                               0.75,  // probability p for IRR
153*2abb3134SXin Li                               0.5);  // probability q for IRR
154*2abb3134SXin Li   EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
155*2abb3134SXin Li                "Assertion.*failed");
156*2abb3134SXin Li   // prob_f > 1.
157*2abb3134SXin Li   delete params;
158*2abb3134SXin Li   params = new rappor::Params(32,    // num_bits (k)
159*2abb3134SXin Li                               2,     // num_hashes (h)
160*2abb3134SXin Li                               1,   // num_cohorts (m)
161*2abb3134SXin Li                               1.1,  // probability f for PRR [BAD]
162*2abb3134SXin Li                               0.75,  // probability p for IRR
163*2abb3134SXin Li                               0.5);  // probability q for IRR
164*2abb3134SXin Li   EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
165*2abb3134SXin Li                "Assertion.*failed");
166*2abb3134SXin Li   // prob_p < 0.
167*2abb3134SXin Li   delete params;
168*2abb3134SXin Li   params = new rappor::Params(32,    // num_bits (k)
169*2abb3134SXin Li                               2,     // num_hashes (h)
170*2abb3134SXin Li                               1,   // num_cohorts (m)
171*2abb3134SXin Li                               0.25,  // probability f for PRR
172*2abb3134SXin Li                               -0.1,  // probability p for IRR [BAD]
173*2abb3134SXin Li                               0.5);  // probability q for IRR
174*2abb3134SXin Li   EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
175*2abb3134SXin Li                "Assertion.*failed");
176*2abb3134SXin Li   // prob_p > 1.
177*2abb3134SXin Li   delete params;
178*2abb3134SXin Li   params = new rappor::Params(32,    // num_bits (k)
179*2abb3134SXin Li                               2,     // num_hashes (h)
180*2abb3134SXin Li                               1,   // num_cohorts (m)
181*2abb3134SXin Li                               0.25,  // probability f for PRR
182*2abb3134SXin Li                               1.1,  // probability p for IRR [BAD]
183*2abb3134SXin Li                               0.5);  // probability q for IRR
184*2abb3134SXin Li   EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
185*2abb3134SXin Li                "Assertion.*failed");
186*2abb3134SXin Li   // prob_q < 0.
187*2abb3134SXin Li   delete params;
188*2abb3134SXin Li   params = new rappor::Params(32,    // num_bits (k)
189*2abb3134SXin Li                               2,     // num_hashes (h)
190*2abb3134SXin Li                               1,   // num_cohorts (m)
191*2abb3134SXin Li                               0.25,  // probability f for PRR
192*2abb3134SXin Li                               0.75,  // probability p for IRR
193*2abb3134SXin Li                               -0.1);  // probability q for IRR [BAD]
194*2abb3134SXin Li   EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
195*2abb3134SXin Li                "Assertion.*failed");
196*2abb3134SXin Li   // prob_q > 1.
197*2abb3134SXin Li   delete params;
198*2abb3134SXin Li   params = new rappor::Params(32,    // num_bits (k)
199*2abb3134SXin Li                               2,     // num_hashes (h)
200*2abb3134SXin Li                               1,   // num_cohorts (m)
201*2abb3134SXin Li                               0.25,  // probability f for PRR
202*2abb3134SXin Li                               0.75,  // probability p for IRR
203*2abb3134SXin Li                               1.1);  // probability q for IRR [BAD]
204*2abb3134SXin Li   EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
205*2abb3134SXin Li                "Assertion.*failed");
206*2abb3134SXin Li }
207*2abb3134SXin Li 
208*2abb3134SXin Li // num_bits 64 when only 32 bits are possible.
TEST_F(EncoderUint32Test,Sha256NoMoreThan32BitsDeathTest)209*2abb3134SXin Li TEST_F(EncoderUint32Test, Sha256NoMoreThan32BitsDeathTest) {
210*2abb3134SXin Li   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
211*2abb3134SXin Li   delete params;
212*2abb3134SXin Li   params = new rappor::Params(64,    // num_bits (k)
213*2abb3134SXin Li                               2,     // num_hashes (h)
214*2abb3134SXin Li                               128,   // num_cohorts (m)
215*2abb3134SXin Li                               0.25,  // probability f for PRR
216*2abb3134SXin Li                               0.75,  // probability p for IRR
217*2abb3134SXin Li                               0.5);  // probability q for IRR
218*2abb3134SXin Li   EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
219*2abb3134SXin Li                "Assertion.*failed");
220*2abb3134SXin Li }
221*2abb3134SXin Li 
222*2abb3134SXin Li // num_hashes too high.
TEST_F(EncoderUint32Test,NumHashesNoMoreThan16DeathTest)223*2abb3134SXin Li TEST_F(EncoderUint32Test, NumHashesNoMoreThan16DeathTest) {
224*2abb3134SXin Li   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
225*2abb3134SXin Li   delete params;
226*2abb3134SXin Li   params = new rappor::Params(32,    // num_bits (k)
227*2abb3134SXin Li                               17,     // num_hashes (h)
228*2abb3134SXin Li                               128,   // num_cohorts (m)
229*2abb3134SXin Li                               0.25,  // probability f for PRR
230*2abb3134SXin Li                               0.75,  // probability p for IRR
231*2abb3134SXin Li                               0.5);  // probability q for IRR
232*2abb3134SXin Li   EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
233*2abb3134SXin Li                "Assertion.*failed");
234*2abb3134SXin Li }
235*2abb3134SXin Li 
236*2abb3134SXin Li // EncoderString with 4-byte vector and HMACSHA256 and
237*2abb3134SXin Li // EncoderString with Uint32 and HMACSHA256 should match.
TEST_F(EncoderUint32Test,StringUint32AndStringVectorMatch)238*2abb3134SXin Li TEST_F(EncoderUint32Test, StringUint32AndStringVectorMatch) {
239*2abb3134SXin Li   ASSERT_TRUE(encoder->EncodeString("foo", &bits_out));
240*2abb3134SXin Li   ASSERT_EQ(2281639167, bits_out);
241*2abb3134SXin Li   std::vector<uint8_t> expected_out(4);
242*2abb3134SXin Li   expected_out[0] = (bits_out & 0xFF000000) >> 24;
243*2abb3134SXin Li   expected_out[1] = (bits_out & 0x00FF0000) >> 16;
244*2abb3134SXin Li   expected_out[2] = (bits_out & 0x0000FF00) >> 8;
245*2abb3134SXin Li   expected_out[3] = bits_out  & 0x000000FF;
246*2abb3134SXin Li 
247*2abb3134SXin Li   // Reset the mock randomizer.
248*2abb3134SXin Li   delete irr_rand;
249*2abb3134SXin Li   delete deps;
250*2abb3134SXin Li   delete encoder;
251*2abb3134SXin Li   fclose(fp);
252*2abb3134SXin Li   fp = mock_urandom();
253*2abb3134SXin Li   irr_rand = new rappor::UnixKernelRand(fp);
254*2abb3134SXin Li   deps = new rappor::Deps(rappor::Md5, "client-secret", rappor::HmacSha256,
255*2abb3134SXin Li                           *irr_rand);
256*2abb3134SXin Li   encoder = new rappor::Encoder(encoder_id, *params, *deps);
257*2abb3134SXin Li   ASSERT_TRUE(encoder->EncodeString("foo", &bits_vector));
258*2abb3134SXin Li   ASSERT_EQ(expected_out, bits_vector);
259*2abb3134SXin Li }
260*2abb3134SXin Li 
261*2abb3134SXin Li ///// EncoderUnlimTest
262*2abb3134SXin Li 
TEST_F(EncoderUnlimTest,EncodeStringUint64)263*2abb3134SXin Li TEST_F(EncoderUnlimTest, EncodeStringUint64) {
264*2abb3134SXin Li   static const uint8_t ex[] = { 134, 255, 11, 255, 252, 119, 240, 223 };
265*2abb3134SXin Li   std::vector<uint8_t> expected_vector(ex, ex + sizeof(ex));
266*2abb3134SXin Li 
267*2abb3134SXin Li   ASSERT_TRUE(encoder->EncodeString("foo", &bits_vector));
268*2abb3134SXin Li   ASSERT_EQ(expected_vector, bits_vector);
269*2abb3134SXin Li   ASSERT_EQ(93, encoder->cohort());
270*2abb3134SXin Li }
271*2abb3134SXin Li 
272*2abb3134SXin Li // Negative tests.
TEST_F(EncoderUnlimTest,NumBitsNotMultipleOf8DeathTest)273*2abb3134SXin Li TEST_F(EncoderUnlimTest, NumBitsNotMultipleOf8DeathTest) {
274*2abb3134SXin Li   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
275*2abb3134SXin Li   delete params;
276*2abb3134SXin Li   params = new rappor::Params(63,    // num_bits (k) [BAD]
277*2abb3134SXin Li                               17,     // num_hashes (h)
278*2abb3134SXin Li                               128,   // num_cohorts (m)
279*2abb3134SXin Li                               0.25,  // probability f for PRR
280*2abb3134SXin Li                               0.75,  // probability p for IRR
281*2abb3134SXin Li                               0.5);  // probability q for IRR
282*2abb3134SXin Li   EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
283*2abb3134SXin Li                "Assertion.*failed");
284*2abb3134SXin Li }
285*2abb3134SXin Li 
main(int argc,char ** argv)286*2abb3134SXin Li int main(int argc, char **argv) {
287*2abb3134SXin Li   ::testing::InitGoogleTest(&argc, argv);
288*2abb3134SXin Li   return RUN_ALL_TESTS();
289*2abb3134SXin Li }
290