1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file.
4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/rappor/rappor_metric.h"
6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <stdlib.h>
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/rand_util.h"
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/strings/stringprintf.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace rappor {
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const RapporParameters kTestRapporParameters = {
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    1 /* Num cohorts */,
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    16 /* Bloom filter size bytes */,
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    4 /* Bloom filter hash count */,
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    PROBABILITY_75 /* Fake data probability */,
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    PROBABILITY_50 /* Fake one probability */,
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    PROBABILITY_75 /* One coin probability */,
22effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    PROBABILITY_50 /* Zero coin probability */};
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const RapporParameters kTestStatsRapporParameters = {
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    1 /* Num cohorts */,
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    50 /* Bloom filter size bytes */,
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    4 /* Bloom filter hash count */,
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    PROBABILITY_75 /* Fake data probability */,
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    PROBABILITY_50 /* Fake one probability */,
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    PROBABILITY_75 /* One coin probability */,
31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    PROBABILITY_50 /* Zero coin probability */};
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Check for basic syntax and use.
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST(RapporMetricTest, BasicMetric) {
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RapporMetric testMetric("MyRappor", kTestRapporParameters, 0);
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  testMetric.AddSample("Bar");
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(0x80, testMetric.bytes()[1]);
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST(RapporMetricTest, GetReport) {
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RapporMetric metric("MyRappor", kTestRapporParameters, 0);
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const ByteVector report = metric.GetReport(
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      HmacByteVectorGenerator::GenerateEntropyInput());
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(16u, report.size());
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TEST(RapporMetricTest, GetReportStatistics) {
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RapporMetric metric("MyStatsRappor", kTestStatsRapporParameters, 0);
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ByteVector real_bits(kTestStatsRapporParameters.bloom_filter_size_bytes);
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Set 152 bits (19 bytes)
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (char i = 0; i < 19; i++) {
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    real_bits[i] = 0xff;
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  metric.SetBytesForTesting(real_bits);
57effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const int real_bit_count = CountBits(real_bits);
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(real_bit_count, 152);
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const std::string secret = HmacByteVectorGenerator::GenerateEntropyInput();
61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const ByteVector report = metric.GetReport(secret);
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // For the bits we actually set in the Bloom filter, get a count of how
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // many of them reported true.
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ByteVector from_true_reports = report;
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Real bits AND report bits.
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ByteVectorMerge(real_bits, real_bits, &from_true_reports);
68effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const int true_from_true_count = CountBits(from_true_reports);
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // For the bits we didn't set in the Bloom filter, get a count of how
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // many of them reported true.
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ByteVector from_false_reports = report;
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ByteVectorOr(real_bits, &from_false_reports);
74effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const int true_from_false_count =
75effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      CountBits(from_false_reports) - real_bit_count;
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The probability of a true bit being true after redaction =
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //   [fake_prob]*[fake_true_prob] + (1-[fake_prob]) =
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //   .75 * .5 + (1-.75) = .625
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The probablity of a false bit being true after redaction =
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //   [fake_prob]*[fake_true_prob] = .375
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The probability of a bit reporting true =
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //   [redacted_prob] * [one_coin_prob:.75] +
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //      (1-[redacted_prob]) * [zero_coin_prob:.5] =
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //   0.65625 for true bits
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //   0.59375 for false bits
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // stats.binom(152, 0.65625).ppf(0.000005) = 73
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_GT(true_from_true_count, 73);
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // stats.binom(152, 0.65625).ppf(0.999995) = 124
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_LE(true_from_true_count, 124);
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // stats.binom(248, 0.59375).ppf(.000005) = 113
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_GT(true_from_false_count, 113);
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // stats.binom(248, 0.59375).ppf(.999995) = 181
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_LE(true_from_false_count, 181);
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace rappor
100