blob: c33c8924963c6da9c0208bc3831f1981ac5b2a32 [file] [log] [blame]
Avi Drissman8ba1bad2022-09-13 19:22:361// Copyright 2022 The Chromium Authors
Yao Xiaodc070d12022-03-08 21:19:132// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/browsing_topics/util.h"
6
Peter Kastingccea09832025-01-27 18:38:227#include <algorithm>
8
Elly4b270c42024-11-26 20:09:049#include "base/numerics/byte_conversions.h"
Yao Xiaodc070d12022-03-08 21:19:1310#include "base/rand_util.h"
Elly15dee24d2025-05-10 01:10:2311#include "crypto/hash.h"
Yao Xiaodc070d12022-03-08 21:19:1312#include "crypto/hmac.h"
Yao Xiaoc95d3152022-03-18 03:43:2213#include "third_party/blink/public/common/features.h"
Yao Xiaodc070d12022-03-08 21:19:1314
15namespace browsing_topics {
16
17namespace {
18
19// Note that updating the use case prefixes below will change the pre-existing
20// per-user stickiness. Some of the derived data may already have been persisted
21// elsewhere. Be sure you are aware of the implications before updating those
22// strings. Note also that the version here is just about the hash method, and
23// is distinctive from the broader configuration version of the Topics API.
24const char kRandomOrTopTopicDecisionPrefix[] =
25 "TopicsV1_RandomOrTopTopicDecision|";
26const char kRandomTopicIndexDecisionPrefix[] =
27 "TopicsV1_RandomTopicIndexDecision|";
28const char kTopTopicIndexDecisionPrefix[] = "TopicsV1_TopTopicIndexDecision|";
Yao Xiao7d287882024-09-28 16:22:3129const char kEpochIntroductionTimeDecisionPrefix[] =
Yao Xiaodc070d12022-03-08 21:19:1330 "TopicsV1_EpochSwitchTimeDecision|";
Yao Xiao7d287882024-09-28 16:22:3131const char kEpochPhaseOutTimeDecisionPrefix[] =
32 "TopicsV1_EpochPhaseOutTimeDecision|";
Yao Xiaodc070d12022-03-08 21:19:1333const char kContextDomainStoragePrefix[] = "TopicsV1_ContextDomainStorage|";
Yao Xiaoc95d3152022-03-18 03:43:2234const char kMainFrameHostStoragePrefix[] = "TopicsV1_MainFrameHostStorage|";
Yao Xiaodc070d12022-03-08 21:19:1335
Yao Xiao0cb3fc12022-03-16 00:30:3836uint64_t HmacHash(ReadOnlyHmacKey hmac_key,
Yao Xiaodc070d12022-03-08 21:19:1337 const std::string& use_case_prefix,
38 const std::string& data) {
Elly4b270c42024-11-26 20:09:0439 auto hash = crypto::hmac::SignSha256(
40 hmac_key, base::as_byte_span(use_case_prefix + data));
41 return base::U64FromNativeEndian(base::span(hash).first<8u>());
Yao Xiaodc070d12022-03-08 21:19:1342}
43
Peter Kasting4f54ba62022-10-29 01:45:0144bool g_hmac_key_overridden = false;
danakj95305d272024-05-09 20:38:4445
Peter Kasting4f54ba62022-10-29 01:45:0146browsing_topics::HmacKey& GetHmacKeyOverrideForTesting() {
47 static browsing_topics::HmacKey key;
48 return key;
49}
Yao Xiao0cb3fc12022-03-16 00:30:3850
Yao Xiao63cc1fc2024-09-25 17:21:5151std::string GetEpochId(base::Time epoch_calculation_time) {
52 int64_t time_microseconds =
53 epoch_calculation_time.ToDeltaSinceWindowsEpoch().InMicroseconds();
54
55 return std::string(reinterpret_cast<const char*>(&time_microseconds),
56 sizeof(time_microseconds));
57}
58
Yao Xiaodc070d12022-03-08 21:19:1359} // namespace
60
Yao Xiaoa7cada472024-04-11 20:44:1961bool DoesCalculationFailDueToHanging(CalculatorResultStatus status) {
62 return status == CalculatorResultStatus::kHangingAfterApiUsageRequested ||
63 status == CalculatorResultStatus::kHangingAfterHistoryRequested ||
64 status == CalculatorResultStatus::kHangingAfterModelRequested ||
65 status == CalculatorResultStatus::kHangingAfterAnnotationRequested;
66}
67
Yao Xiao0cb3fc12022-03-16 00:30:3868HmacKey GenerateRandomHmacKey() {
Peter Kasting4f54ba62022-10-29 01:45:0169 if (g_hmac_key_overridden)
70 return GetHmacKeyOverrideForTesting();
Yao Xiao0cb3fc12022-03-16 00:30:3871
72 HmacKey result = {};
danakj95305d272024-05-09 20:38:4473 base::RandBytes(result);
Yao Xiaodc070d12022-03-08 21:19:1374
75 return result;
76}
77
78uint64_t HashTopDomainForRandomOrTopTopicDecision(
Yao Xiao0cb3fc12022-03-16 00:30:3879 ReadOnlyHmacKey hmac_key,
Yao Xiaodc070d12022-03-08 21:19:1380 base::Time epoch_calculation_time,
81 const std::string& top_domain) {
Yao Xiaodc070d12022-03-08 21:19:1382 return HmacHash(hmac_key, kRandomOrTopTopicDecisionPrefix,
Yao Xiao63cc1fc2024-09-25 17:21:5183 GetEpochId(epoch_calculation_time) + top_domain);
Yao Xiaodc070d12022-03-08 21:19:1384}
85
86uint64_t HashTopDomainForRandomTopicIndexDecision(
Yao Xiao0cb3fc12022-03-16 00:30:3887 ReadOnlyHmacKey hmac_key,
Yao Xiaodc070d12022-03-08 21:19:1388 base::Time epoch_calculation_time,
89 const std::string& top_domain) {
Yao Xiaodc070d12022-03-08 21:19:1390 return HmacHash(hmac_key, kRandomTopicIndexDecisionPrefix,
Yao Xiao63cc1fc2024-09-25 17:21:5191 GetEpochId(epoch_calculation_time) + top_domain);
Yao Xiaodc070d12022-03-08 21:19:1392}
93
94uint64_t HashTopDomainForTopTopicIndexDecision(
Yao Xiao0cb3fc12022-03-16 00:30:3895 ReadOnlyHmacKey hmac_key,
Yao Xiaodc070d12022-03-08 21:19:1396 base::Time epoch_calculation_time,
97 const std::string& top_domain) {
Yao Xiaodc070d12022-03-08 21:19:1398 return HmacHash(hmac_key, kTopTopicIndexDecisionPrefix,
Yao Xiao63cc1fc2024-09-25 17:21:5199 GetEpochId(epoch_calculation_time) + top_domain);
Yao Xiaodc070d12022-03-08 21:19:13100}
101
Yao Xiao7d287882024-09-28 16:22:31102uint64_t HashTopDomainForEpochIntroductionTimeDecision(
Yao Xiao0cb3fc12022-03-16 00:30:38103 ReadOnlyHmacKey hmac_key,
Yao Xiao63cc1fc2024-09-25 17:21:51104 base::Time epoch_calculation_time,
Yao Xiaodc070d12022-03-08 21:19:13105 const std::string& top_domain) {
Yao Xiao7d287882024-09-28 16:22:31106 return HmacHash(hmac_key, kEpochIntroductionTimeDecisionPrefix,
107 GetEpochId(epoch_calculation_time) + top_domain);
108}
109
110uint64_t HashTopDomainForEpochPhaseOutTimeDecision(
111 ReadOnlyHmacKey hmac_key,
112 base::Time epoch_calculation_time,
113 const std::string& top_domain) {
114 return HmacHash(hmac_key, kEpochPhaseOutTimeDecisionPrefix,
Yao Xiao63cc1fc2024-09-25 17:21:51115 GetEpochId(epoch_calculation_time) + top_domain);
Yao Xiaodc070d12022-03-08 21:19:13116}
117
Yao Xiao0cb3fc12022-03-16 00:30:38118HashedDomain HashContextDomainForStorage(ReadOnlyHmacKey hmac_key,
Yao Xiaodc070d12022-03-08 21:19:13119 const std::string& context_domain) {
120 return HashedDomain(
121 HmacHash(hmac_key, kContextDomainStoragePrefix, context_domain));
122}
123
Yao Xiaoc95d3152022-03-18 03:43:22124HashedHost HashMainFrameHostForStorage(const std::string& main_frame_host) {
Elly15dee24d2025-05-10 01:10:23125 auto hash =
126 crypto::hash::Sha256(kMainFrameHostStoragePrefix + main_frame_host);
127 int64_t result = base::I64FromNativeEndian(base::span(hash).first<8u>());
Yao Xiaodc070d12022-03-08 21:19:13128 return HashedHost(result);
129}
130
Yao Xiao0cb3fc12022-03-16 00:30:38131void OverrideHmacKeyForTesting(ReadOnlyHmacKey hmac_key) {
Peter Kasting4f54ba62022-10-29 01:45:01132 g_hmac_key_overridden = true;
Peter Kastingccea09832025-01-27 18:38:22133 std::ranges::copy(hmac_key, GetHmacKeyOverrideForTesting().begin());
Yao Xiao0cb3fc12022-03-16 00:30:38134}
135
Yao Xiaodc070d12022-03-08 21:19:13136} // namespace browsing_topics