Mike Jackson | 82654a3a | 2025-02-13 07:48:22 | [diff] [blame] | 1 | // Copyright 2025 The Chromium Authors |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "content/browser/renderer_host/randomized_confidence_utils.h" |
| 6 | |
| 7 | #include "base/rand_util.h" |
| 8 | #include "content/public/common/content_features.h" |
| 9 | |
| 10 | namespace content { |
| 11 | |
| 12 | double GetConfidenceRandomizedTriggerRate() { |
| 13 | // A value of 18 here is large enough that computing the |
| 14 | // navigation flip probability returns 0. |
| 15 | static double g_max_navigation_confidence_epsilon = 18; |
| 16 | |
| 17 | int32_t state_count = 1 + (int32_t)blink::mojom::ConfidenceLevel::kMaxValue; |
| 18 | double navigation_confidence_epsilon = std::max( |
| 19 | 0.0, std::min(g_max_navigation_confidence_epsilon, |
| 20 | features::kNavigationConfidenceEpsilonValue.Get())); |
| 21 | double randomized_response_rate = |
| 22 | state_count / |
| 23 | ((state_count - 1) + std::exp(navigation_confidence_epsilon)); |
| 24 | double rounded_rate = round(randomized_response_rate * 10000000) / 10000000.0; |
| 25 | return std::max(0.0, std::min(1.0, rounded_rate)); |
| 26 | } |
| 27 | |
| 28 | blink::mojom::ConfidenceLevel GenerateRandomizedConfidenceLevel( |
| 29 | double randomizedTriggerRate, |
| 30 | blink::mojom::ConfidenceLevel confidence) { |
| 31 | // Encode the confidence using differential-privacy scheme as described in |
| 32 | // https://blog.chromium.org/2014/10/learning-statistics-with-privacy-aided.html |
| 33 | // |
| 34 | // The general algorithm is: |
| 35 | // - Toss a coin. |
| 36 | // - If heads answer the question honestly. |
| 37 | // - If tails, then toss the coin again and answer "high" if heads, |
| 38 | // "low" if tails. |
| 39 | blink::mojom::ConfidenceLevel maybe_flipped_confidence = confidence; |
| 40 | |
| 41 | // Step 1: Toss a coin, by generating a random double with a value between 0 |
| 42 | // and 1. |
| 43 | float first_coin_flip = base::RandDouble(); |
| 44 | |
| 45 | // Step 2: If the random number is greater than or equal to the flip |
| 46 | // probability (heads), use the computed confidence level. |
| 47 | if (first_coin_flip < randomizedTriggerRate) { |
| 48 | // Step 3: If the random number is less than the flip probability |
| 49 | // (tails), toss the coin again by generating a random integer with a |
| 50 | // value of either 0 or 1. If 0 (heads), return |
| 51 | // `ConfidenceLevel::kHigh` else return `ConfidenceLevel::kLow`. |
| 52 | int second_coin_flip = base::RandInt(0, 1); |
| 53 | maybe_flipped_confidence = second_coin_flip == 0 |
| 54 | ? blink::mojom::ConfidenceLevel::kHigh |
| 55 | : blink::mojom::ConfidenceLevel::kLow; |
| 56 | } |
| 57 | |
| 58 | return maybe_flipped_confidence; |
| 59 | } |
| 60 | |
| 61 | } // namespace content |