[Identifiability Study] Add noise to Reid estimation

In this CL we add code for adding noise to the Reid score estimation with a probability controlled by a feature parameter. This CL is a continuation of the POC to estimate the REID score of sets of surfaces defined by the feature parameter kIdentifiabilityStudyReidSurfaceBlocks.

We add one feature setting that can be set from server-side:
kIdentifiabilityStudyReidSurfaceBlocksNoise. This parameter sets the probability of noise to be reported when computing the REID hash for the relative block of surfaces defined in kIdentifiabilityStudyReidSurfaceBlocks parameter.

Bug: 1330244
Change-Id: I0a7de4379a959a3be503cf2d01ef68ba283d9f40
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3771820
Commit-Queue: Saeid Eid <saeideid@chromium.org>
Reviewed-by: Antonio Sartori <antoniosartori@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1026185}
diff --git a/chrome/browser/privacy_budget/identifiability_study_group_settings.cc b/chrome/browser/privacy_budget/identifiability_study_group_settings.cc
index 035515c1..c6af150 100644
--- a/chrome/browser/privacy_budget/identifiability_study_group_settings.cc
+++ b/chrome/browser/privacy_budget/identifiability_study_group_settings.cc
@@ -34,7 +34,8 @@
       features::kIdentifiabilityStudyAllowedRandomTypes.Get(),
       features::kIdentifiabilityStudyReidSurfaceBlocks.Get(),
       features::kIdentifiabilityStudyReidSurfaceBlocksSaltsRanges.Get(),
-      features::kIdentifiabilityStudyReidSurfaceBlocksBits.Get());
+      features::kIdentifiabilityStudyReidSurfaceBlocksBits.Get(),
+      features::kIdentifiabilityStudyReidBlocksNoiseProbabilities.Get());
 }
 
 // static
@@ -47,7 +48,8 @@
     const std::string& allowed_random_types,
     const std::string& reid_blocks,
     const std::string& reid_blocks_salts_ranges,
-    const std::string& reid_blocks_bits) {
+    const std::string& reid_blocks_bits,
+    const std::string& reid_blocks_noise_probabilities) {
   return IdentifiabilityStudyGroupSettings(
       enabled, expected_surface_count, surface_budget,
       DecodeIdentifiabilityFieldTrialParam<IdentifiableSurfaceBlocks>(blocks),
@@ -58,7 +60,9 @@
           reid_blocks),
       DecodeIdentifiabilityFieldTrialParam<std::vector<uint64_t>>(
           reid_blocks_salts_ranges),
-      DecodeIdentifiabilityFieldTrialParam<std::vector<int>>(reid_blocks_bits));
+      DecodeIdentifiabilityFieldTrialParam<std::vector<int>>(reid_blocks_bits),
+      DecodeIdentifiabilityFieldTrialParam<std::vector<double>>(
+          reid_blocks_noise_probabilities));
 }
 
 IdentifiabilityStudyGroupSettings::IdentifiabilityStudyGroupSettings(
@@ -70,7 +74,8 @@
     std::vector<blink::IdentifiableSurface::Type> allowed_random_types,
     IdentifiableSurfaceBlocks reid_blocks,
     std::vector<uint64_t> reid_blocks_salts_ranges,
-    std::vector<int> reid_blocks_bits)
+    std::vector<int> reid_blocks_bits,
+    std::vector<double> reid_blocks_noise_probabilities)
     : enabled_(enabled),
       expected_surface_count_(base::clamp<int>(
           expected_surface_count,
@@ -85,6 +90,8 @@
       reid_blocks_(std::move(reid_blocks)),
       reid_blocks_salts_ranges_(std::move(reid_blocks_salts_ranges)),
       reid_blocks_bits_(std::move(reid_blocks_bits)),
+      reid_blocks_noise_probabilities_(
+          std::move(reid_blocks_noise_probabilities)),
       allowed_random_types_(std::move(allowed_random_types)) {
   bool validates = Validate();
   UmaHistogramFinchConfigValidation(validates);
@@ -155,15 +162,22 @@
 
 bool IdentifiabilityStudyGroupSettings::ValidateReidBlockEstimator() {
   if (reid_blocks_salts_ranges_.size() != reid_blocks_.size() ||
-      reid_blocks_bits_.size() != reid_blocks_.size())
+      reid_blocks_bits_.size() != reid_blocks_.size() ||
+      reid_blocks_noise_probabilities_.size() != reid_blocks_.size())
     return false;
-  bool valid_ranges =
+  bool valid_params =
       base::ranges::all_of(reid_blocks_salts_ranges_,
                            [](uint64_t salt_range) { return salt_range > 0; });
-  return valid_ranges &&
-         base::ranges::all_of(reid_blocks_bits_, [](int reid_bits) {
-           return reid_bits > 0 && reid_bits <= 32;
-         });
+  valid_params = valid_params &&
+                 base::ranges::all_of(reid_blocks_bits_, [](int reid_bits) {
+                   return reid_bits > 0 && reid_bits <= 32;
+                 });
+
+  return valid_params && base::ranges::all_of(reid_blocks_noise_probabilities_,
+                                              [](double reid_noise) {
+                                                return reid_noise >= 0 &&
+                                                       reid_noise <= 1;
+                                              });
 }
 
 const IdentifiableSurfaceBlocks& IdentifiabilityStudyGroupSettings::blocks()
@@ -186,6 +200,11 @@
   return reid_blocks_bits_;
 }
 
+const std::vector<double>&
+IdentifiabilityStudyGroupSettings::reid_blocks_noise_probabilities() const {
+  return reid_blocks_noise_probabilities_;
+}
+
 const IdentifiableSurfaceBlocks&
 IdentifiabilityStudyGroupSettings::reid_blocks() const {
   return reid_blocks_;
diff --git a/chrome/browser/privacy_budget/identifiability_study_group_settings.h b/chrome/browser/privacy_budget/identifiability_study_group_settings.h
index 8556493..0c32a9c 100644
--- a/chrome/browser/privacy_budget/identifiability_study_group_settings.h
+++ b/chrome/browser/privacy_budget/identifiability_study_group_settings.h
@@ -28,7 +28,8 @@
       const std::string& allowed_random_types,
       const std::string& reid_blocks,
       const std::string& reid_blocks_salts_ranges,
-      const std::string& reid_blocks_bits);
+      const std::string& reid_blocks_bits,
+      const std::string& reid_blocks_noise_probabilities);
 
   IdentifiabilityStudyGroupSettings(const IdentifiabilityStudyGroupSettings&) =
       delete;
@@ -56,6 +57,7 @@
   const std::vector<double>& blocks_weights() const;
   const std::vector<uint64_t>& reid_blocks_salts_ranges() const;
   const std::vector<int>& reid_blocks_bits() const;
+  const std::vector<double>& reid_blocks_noise_probabilities() const;
   const std::vector<blink::IdentifiableSurface::Type>& allowed_random_types()
       const;
 
@@ -72,7 +74,8 @@
       std::vector<blink::IdentifiableSurface::Type> allowed_random_types,
       IdentifiableSurfaceBlocks reid_blocks,
       std::vector<uint64_t> reid_blocks_salts_ranges,
-      std::vector<int> reid_blocks_bits);
+      std::vector<int> reid_blocks_bits,
+      std::vector<double> reid_blocks_noise_probabilities);
 
   bool Validate();
   bool ValidateAssignedBlockSampling();
@@ -96,6 +99,8 @@
 
   const std::vector<int> reid_blocks_bits_;
 
+  const std::vector<double> reid_blocks_noise_probabilities_;
+
   // Surface types to sample from when random surface sampling is enabled. If
   // this vector is empty all surface types are allowed to be sampled.
   const std::vector<blink::IdentifiableSurface::Type> allowed_random_types_;
diff --git a/chrome/browser/privacy_budget/identifiability_study_group_settings_unittest.cc b/chrome/browser/privacy_budget/identifiability_study_group_settings_unittest.cc
index bcdc2bb7..e435840 100644
--- a/chrome/browser/privacy_budget/identifiability_study_group_settings_unittest.cc
+++ b/chrome/browser/privacy_budget/identifiability_study_group_settings_unittest.cc
@@ -14,7 +14,7 @@
 
 TEST_F(IdentifiabilityStudyGroupSettingsTest, Disabled) {
   auto settings = IdentifiabilityStudyGroupSettings::InitFrom(
-      false, 0, 0, "", "", "", "", "", "");
+      false, 0, 0, "", "", "", "", "", "", "");
   EXPECT_FALSE(settings.enabled());
   histogram_tester.ExpectUniqueSample(
       "PrivacyBudget.Identifiability.FinchConfigValidationResult", true, 1);
@@ -22,7 +22,7 @@
 
 TEST_F(IdentifiabilityStudyGroupSettingsTest, DisabledWithParams) {
   auto settings = IdentifiabilityStudyGroupSettings::InitFrom(
-      false, 10, 40, "", "", "", "", "", "");
+      false, 10, 40, "", "", "", "", "", "", "");
   EXPECT_FALSE(settings.enabled());
   histogram_tester.ExpectUniqueSample(
       "PrivacyBudget.Identifiability.FinchConfigValidationResult", true, 1);
@@ -30,7 +30,7 @@
 
 TEST_F(IdentifiabilityStudyGroupSettingsTest, DisabledBySurfaceCountZero) {
   auto settings = IdentifiabilityStudyGroupSettings::InitFrom(
-      true, 0, 40, "", "", "", "", "", "");
+      true, 0, 40, "", "", "", "", "", "", "");
   EXPECT_FALSE(settings.enabled());
   histogram_tester.ExpectUniqueSample(
       "PrivacyBudget.Identifiability.FinchConfigValidationResult", false, 1);
@@ -38,7 +38,7 @@
 
 TEST_F(IdentifiabilityStudyGroupSettingsTest, ValidRandomSurfaceSampling) {
   auto settings = IdentifiabilityStudyGroupSettings::InitFrom(
-      true, 10, 40, "", "", "1,4", "", "", "");
+      true, 10, 40, "", "", "1,4", "", "", "", "");
   EXPECT_TRUE(settings.enabled());
   EXPECT_FALSE(settings.IsUsingAssignedBlockSampling());
   EXPECT_TRUE(settings.IsUsingRandomSampling());
@@ -56,7 +56,7 @@
 
 TEST_F(IdentifiabilityStudyGroupSettingsTest, ValidAssignedBlockSampling) {
   auto settings = IdentifiabilityStudyGroupSettings::InitFrom(
-      true, 0, 0, "1;2,3;4,5;6", "1,1,1", "", "", "", "");
+      true, 0, 0, "1;2,3;4,5;6", "1,1,1", "", "", "", "", "");
   EXPECT_TRUE(settings.enabled());
   EXPECT_TRUE(settings.IsUsingAssignedBlockSampling());
   EXPECT_FALSE(settings.IsUsingRandomSampling());
@@ -67,7 +67,7 @@
 
 TEST_F(IdentifiabilityStudyGroupSettingsTest, InvalidNegativeWeight) {
   auto settings = IdentifiabilityStudyGroupSettings::InitFrom(
-      true, 0, 0, "1;2,3;4,5;6", "-1,1,1", "", "", "", "");
+      true, 0, 0, "1;2,3;4,5;6", "-1,1,1", "", "", "", "", "");
   EXPECT_FALSE(settings.enabled());
   histogram_tester.ExpectUniqueSample(
       "PrivacyBudget.Identifiability.FinchConfigValidationResult", false, 1);
@@ -75,7 +75,7 @@
 
 TEST_F(IdentifiabilityStudyGroupSettingsTest, InvalidSurfaceTooLikely) {
   auto settings = IdentifiabilityStudyGroupSettings::InitFrom(
-      true, 0, 0, "1;2,1;4,5;6", "1,1,1", "", "", "", "");
+      true, 0, 0, "1;2,1;4,5;6", "1,1,1", "", "", "", "", "");
   EXPECT_FALSE(settings.enabled());
   histogram_tester.ExpectUniqueSample(
       "PrivacyBudget.Identifiability.FinchConfigValidationResult", false, 1);
@@ -83,7 +83,7 @@
 
 TEST_F(IdentifiabilityStudyGroupSettingsTest, EnableSettingsForValidReidBlock) {
   auto settings = IdentifiabilityStudyGroupSettings::InitFrom(
-      true, 0, 0, "", "", "", "1;2,4;5;6", "2,2", "2,3");
+      true, 0, 0, "", "", "", "1;2,4;5;6", "2,2", "2,3", "0.1,0.2");
   EXPECT_TRUE(settings.IsUsingReidScoreEstimator());
   EXPECT_FALSE(settings.IsUsingSamplingOfSurfaces());
   EXPECT_TRUE(settings.enabled());
@@ -93,7 +93,7 @@
 
 TEST_F(IdentifiabilityStudyGroupSettingsTest, InvalidReidBlocks) {
   auto settings = IdentifiabilityStudyGroupSettings::InitFrom(
-      true, 0, 0, "", "", "", "1;2,4;5;6", "2", "2,3");
+      true, 0, 0, "", "", "", "1;2,4;5;6", "2", "2,3", "0.1,0.2");
   EXPECT_FALSE(settings.enabled());
   histogram_tester.ExpectUniqueSample(
       "PrivacyBudget.Identifiability.FinchConfigValidationResult", false, 1);
diff --git a/chrome/browser/privacy_budget/privacy_budget_reid_score_browsertest.cc b/chrome/browser/privacy_budget/privacy_budget_reid_score_browsertest.cc
index 3100734e..e29720ab 100644
--- a/chrome/browser/privacy_budget/privacy_budget_reid_score_browsertest.cc
+++ b/chrome/browser/privacy_budget/privacy_budget_reid_score_browsertest.cc
@@ -42,6 +42,7 @@
 
     parameters.reid_salts_ranges = {1};
     parameters.reid_bits = {1};
+    parameters.reid_noise = {0.01};
 
     scoped_config_.Apply(parameters);
   }
diff --git a/chrome/browser/privacy_budget/privacy_budget_reid_score_estimator.cc b/chrome/browser/privacy_budget/privacy_budget_reid_score_estimator.cc
index 46fd54d..bd27dfb 100644
--- a/chrome/browser/privacy_budget/privacy_budget_reid_score_estimator.cc
+++ b/chrome/browser/privacy_budget/privacy_budget_reid_score_estimator.cc
@@ -40,6 +40,8 @@
   IdentifiableSurfaceBlocks reid_blocks = state_settings.reid_blocks();
   reid_blocks_salts_ranges_ = state_settings.reid_blocks_salts_ranges();
   reid_blocks_bits_ = state_settings.reid_blocks_bits();
+  reid_blocks_noise_probabilities_ =
+      state_settings.reid_blocks_noise_probabilities();
 
   // Step 2: Get the type of the Reid surface.
   constexpr auto kReidScoreType =
@@ -93,7 +95,7 @@
           // Compute the Reid hash for the needed Reid block.
           uint64_t reid_hash = ComputeHashForReidScore(
               *surface_map, reid_blocks_salts_ranges_.at(i),
-              reid_blocks_bits_.at(i));
+              reid_blocks_bits_.at(i), reid_blocks_noise_probabilities_.at(i));
           // Report to UKM in a separate task in order to avoid re-entrancy.
           base::SequencedTaskRunnerHandle::Get()->PostTask(
               FROM_HERE, base::BindOnce(&ReportHashForReidScore, map_itr.first,
@@ -108,7 +110,8 @@
 uint64_t PrivacyBudgetReidScoreEstimator::ComputeHashForReidScore(
     const SurfacesAndOptionalValues& surface_map,
     uint64_t max_num_salt,
-    int reid_bits) {
+    int reid_bits,
+    double reid_noise_probability) {
   std::vector<uint64_t> tokens;
   uint64_t salt = base::RandGenerator(max_num_salt);
 
@@ -117,11 +120,18 @@
     tokens.emplace_back(
         static_cast<uint64_t>(surface_itr.second->ToUkmMetricValue()));
   }
-  // Use the hash function embedded in IdentifiableToken.
-  uint64_t reid_hash = blink::IdentifiabilityDigestOfBytes(
-      base::as_bytes(base::make_span(tokens)));
+  // Initialize Reid hash with random noise.
+  uint64_t reid_hash = base::RandUint64();
+  // Calculate the real hash if the random number is greater than the Reid noise
+  // probability.
+  if (base::RandDouble() >= reid_noise_probability) {
+    // Use the hash function embedded in IdentifiableToken.
+    reid_hash = blink::IdentifiabilityDigestOfBytes(
+        base::as_bytes(base::make_span(tokens)));
+  }
   // Create mask based on reid_bits required.
-  uint64_t mask = (1 << reid_bits) - 1;
+  constexpr uint64_t kTypedOne = 1;
+  uint64_t mask = (kTypedOne << reid_bits) - 1;
   uint64_t needed_bits = reid_hash & mask;
   // Return salt in the left 32 bits and Reid b-bits hash in the right 32 bits.
   return ((salt << 32) | needed_bits);
diff --git a/chrome/browser/privacy_budget/privacy_budget_reid_score_estimator.h b/chrome/browser/privacy_budget/privacy_budget_reid_score_estimator.h
index b251286..d8365df 100644
--- a/chrome/browser/privacy_budget/privacy_budget_reid_score_estimator.h
+++ b/chrome/browser/privacy_budget/privacy_budget_reid_score_estimator.h
@@ -43,6 +43,10 @@
   // surface block.
   std::vector<int> reid_blocks_bits_;
 
+  // Keeps track of the probability of noise that should be reported for every
+  // Reid surface block.
+  std::vector<double> reid_blocks_noise_probabilities_;
+
   // Keeps track of the number of reported surfaces in every Reid surface block.
   // The Reid surface map at index i is full when the count_flag_ at i is equal
   // to the number of surfaces in that map i.e. size of the map.
@@ -51,7 +55,8 @@
   // Compute the hash for estimating the REID score.
   uint64_t ComputeHashForReidScore(const SurfacesAndOptionalValues& surface_map,
                                    uint64_t max_num_salt,
-                                   int reid_bits);
+                                   int reid_bits,
+                                   double reid_noise_probability);
 };
 
 #endif  // CHROME_BROWSER_PRIVACY_BUDGET_PRIVACY_BUDGET_UKM_ENTRY_FILTER_H_
diff --git a/chrome/browser/privacy_budget/privacy_budget_reid_score_estimator_unittest.cc b/chrome/browser/privacy_budget/privacy_budget_reid_score_estimator_unittest.cc
index 611c6c0..d1881a0 100644
--- a/chrome/browser/privacy_budget/privacy_budget_reid_score_estimator_unittest.cc
+++ b/chrome/browser/privacy_budget/privacy_budget_reid_score_estimator_unittest.cc
@@ -5,6 +5,7 @@
 #include <cstdint>
 
 #include "base/barrier_closure.h"
+#include "base/containers/flat_set.h"
 #include "base/rand_util.h"
 #include "base/test/task_environment.h"
 #include "chrome/browser/privacy_budget/identifiability_study_group_settings.h"
@@ -17,7 +18,7 @@
 TEST(PrivacyBudgetReidScoreEstimatorStandaloneTest,
      ReportReidFixedTokenRandomSalt) {
   auto settings = IdentifiabilityStudyGroupSettings::InitFrom(
-      true, 0, 0, "", "", "", "2077075229;1122849309", "1000000", "1");
+      true, 0, 0, "", "", "", "2077075229;1122849309", "1000000", "1", "0");
 
   constexpr auto surface_1 =
       blink::IdentifiableSurface::FromMetricHash(2077075229u);
@@ -78,7 +79,7 @@
 TEST(PrivacyBudgetReidScoreEstimatorStandaloneTest,
      ReportReidRandomTokenFixedSalt) {
   auto settings = IdentifiabilityStudyGroupSettings::InitFrom(
-      true, 0, 0, "", "", "", "2077075229;1122849309", "1", "1");
+      true, 0, 0, "", "", "", "2077075229;1122849309", "1", "1", "0");
   constexpr auto surface_1 =
       blink::IdentifiableSurface::FromMetricHash(2077075229u);
   constexpr auto surface_2 =
@@ -134,3 +135,57 @@
   EXPECT_TRUE(has_value_0);
   EXPECT_TRUE(has_value_1);
 }
+
+TEST(PrivacyBudgetReidScoreEstimatorStandaloneTest,
+     ReportReidFixedTokenFixedSaltAllNoise) {
+  auto settings = IdentifiabilityStudyGroupSettings::InitFrom(
+      true, 0, 0, "", "", "", "2077075229;1122849309", "1", "32", "1");
+
+  constexpr auto surface_1 =
+      blink::IdentifiableSurface::FromMetricHash(2077075229u);
+  constexpr auto surface_2 =
+      blink::IdentifiableSurface::FromMetricHash(1122849309u);
+
+  int64_t token1 = 1234;
+  int64_t token2 = 12345;
+  constexpr int num_iterations = 50;
+  base::test::SingleThreadTaskEnvironment task_environment;
+  ukm::TestAutoSetUkmRecorder test_recorder;
+  base::RunLoop run_loop;
+  test_recorder.SetOnAddEntryCallback(
+      ukm::builders::Identifiability::kEntryName,
+      base::BarrierClosure(num_iterations, run_loop.QuitClosure()));
+  blink::test::ScopedIdentifiabilityTestSampleCollector collector;
+  for (int i = 0; i < num_iterations; ++i) {
+    auto reid_storage =
+        std::make_unique<PrivacyBudgetReidScoreEstimator>(settings);
+    // Process values for 2 surfaces.
+    reid_storage->ProcessForReidScore(surface_1,
+                                      blink::IdentifiableToken(token1));
+    reid_storage->ProcessForReidScore(surface_2,
+                                      blink::IdentifiableToken(token2));
+  }
+  // This should let the async tasks run.
+  run_loop.Run();
+  const auto& entries = collector.entries();
+  base::flat_set<uint32_t> reid_results;
+  int count = 0;
+  for (auto& entry : entries) {
+    for (auto& metric : entry.metrics) {
+      auto surface = metric.surface;
+      if (surface.GetType() ==
+          blink::IdentifiableSurface::Type::kReidScoreEstimator) {
+        EXPECT_EQ(metric.surface.ToUkmMetricHash(), 7415899889871487013u);
+        ++count;
+        uint64_t hash = static_cast<uint64_t>(metric.value.ToUkmMetricValue());
+        uint32_t reid_bits = hash & 0xFFFFFFFF;
+        // Result should be noise i.e. didn't appeared before.
+        EXPECT_FALSE(reid_results.contains(reid_bits));
+        reid_results.insert(reid_bits);
+        uint32_t salt = (hash >> 32);
+        EXPECT_EQ(salt, 0u);
+      }
+    }
+  }
+  EXPECT_EQ(count, num_iterations);
+}
diff --git a/chrome/common/privacy_budget/privacy_budget_features.cc b/chrome/common/privacy_budget/privacy_budget_features.cc
index fffd844e..8745ba8 100644
--- a/chrome/common/privacy_budget/privacy_budget_features.cc
+++ b/chrome/common/privacy_budget/privacy_budget_features.cc
@@ -62,5 +62,8 @@
 const base::FeatureParam<std::string>
     kIdentifiabilityStudyReidSurfaceBlocksBits = {&kIdentifiabilityStudy,
                                                   "ReidBlocksBits", ""};
+const base::FeatureParam<std::string>
+    kIdentifiabilityStudyReidBlocksNoiseProbabilities = {
+        &kIdentifiabilityStudy, "ReidBlocksNoiseProbabilities", ""};
 
 }  // namespace features
diff --git a/chrome/common/privacy_budget/privacy_budget_features.h b/chrome/common/privacy_budget/privacy_budget_features.h
index 627c0db..472a26a 100644
--- a/chrome/common/privacy_budget/privacy_budget_features.h
+++ b/chrome/common/privacy_budget/privacy_budget_features.h
@@ -400,6 +400,27 @@
 extern const base::FeatureParam<std::string>
     kIdentifiabilityStudyReidSurfaceBlocksBits;
 
+// Probabilities of reporting noise in Reid estimation.
+//
+// Parameter name: "ReidBlocksNoiseProbabilities"
+// Parameter type: Comma separated list of noise probabilities represented as
+// decimals.
+//
+// If this parameter is specified then it must specify the probability of noise
+// that should be reported for each block that is defined using the `ReidBlocks`
+// parameter. The probability should be a decimal between 0 and 1.
+//
+// * All probabilities must be positive decimals between 0 and 1.
+//
+// * There must be exactly as many Reid noise probabilities as there are Reid
+// blocks. If not, disable the Reid estimator feature.
+//
+// E.g.:
+//   * "0.1,0.05": Assigns probabilities of noise that should be reported from
+//   two Reid Blocks sent in the `ReidBlocks` parameter.
+extern const base::FeatureParam<std::string>
+    kIdentifiabilityStudyReidBlocksNoiseProbabilities;
+
 }  // namespace features
 
 #endif  // CHROME_COMMON_PRIVACY_BUDGET_PRIVACY_BUDGET_FEATURES_H_
diff --git a/chrome/common/privacy_budget/scoped_privacy_budget_config.cc b/chrome/common/privacy_budget/scoped_privacy_budget_config.cc
index b2375db..505895c6 100644
--- a/chrome/common/privacy_budget/scoped_privacy_budget_config.cc
+++ b/chrome/common/privacy_budget/scoped_privacy_budget_config.cc
@@ -130,6 +130,11 @@
     ftp.insert({features::kIdentifiabilityStudyReidSurfaceBlocksBits.name,
                 EncodeIdentifiabilityFieldTrialParam(parameters.reid_bits)});
   }
+  if (!parameters.reid_noise.empty()) {
+    ftp.insert(
+        {features::kIdentifiabilityStudyReidBlocksNoiseProbabilities.name,
+         EncodeIdentifiabilityFieldTrialParam(parameters.reid_noise)});
+  }
   if (!parameters.per_surface_cost.empty()) {
     ftp.insert(
         {features::kIdentifiabilityStudyPerHashCost.name,
diff --git a/chrome/common/privacy_budget/scoped_privacy_budget_config.h b/chrome/common/privacy_budget/scoped_privacy_budget_config.h
index d4e32b61..befb6fac 100644
--- a/chrome/common/privacy_budget/scoped_privacy_budget_config.h
+++ b/chrome/common/privacy_budget/scoped_privacy_budget_config.h
@@ -67,6 +67,7 @@
     IdentifiableSurfaceBlocks reid_blocks;
     std::vector<uint64_t> reid_salts_ranges;
     std::vector<int> reid_bits;
+    std::vector<double> reid_noise;
     std::vector<blink::IdentifiableSurface::Type> allowed_random_types;
     bool enable_active_sampling = false;
     std::vector<std::string> actively_sampled_fonts;
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 0a67e0b..2e72d5eb 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -5104,6 +5104,7 @@
                         "Gen": "8",
                         "ReidBlocks": "18009598079355128088,9223784233214641190;10735872651981970214",
                         "ReidBlocksBits": "1,4",
+                        "ReidBlocksNoiseProbabilities": "0.01,0.01",
                         "ReidBlocksSaltsRanges": "1000,1000000"
                     },
                     "enable_features": [