Commit e02c1e0b authored by Caleb Raitto's avatar Caleb Raitto Committed by Commit Bot

Switch digest calculation from using xor.

The problem with xor is it's a commutative operator, so the relative
ordering of operations won't be captured in the digest calculated.

This is problematic, as drawing an oval and then a rectangle can produce
visually-different results than drawing the rectangle and then the oval.

Instead, we can use the IdentifiableTokenBuilder library, which was
designed to preserve such ordering.

Bug: 973801
Change-Id: I45baf54418263a1984bc3446233fd5a7d0a6ebc3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2311059
Commit-Queue: Caleb Raitto <caraitto@chromium.org>
Reviewed-by: default avatarFernando Serboncini <fserb@chromium.org>
Reviewed-by: default avatarKhushal <khushalsagar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#795677}
parent 246f0a18
...@@ -276,7 +276,7 @@ void HTMLCanvasElement::IdentifiabilityReportWithDigest( ...@@ -276,7 +276,7 @@ void HTMLCanvasElement::IdentifiabilityReportWithDigest(
: nullptr; : nullptr;
const uint64_t canvas_digest = const uint64_t canvas_digest =
identifiability_paintop_digest identifiability_paintop_digest
? identifiability_paintop_digest->digest() ? identifiability_paintop_digest->GetToken().ToUkmMetricValue()
: 0; : 0;
const uint64_t context_type = const uint64_t context_type =
context_ ? context_->GetContextType() context_ ? context_->GetContextType()
......
...@@ -114,7 +114,7 @@ void IdentifiabilityPaintOpDigest::MaybeUpdateDigest( ...@@ -114,7 +114,7 @@ void IdentifiabilityPaintOpDigest::MaybeUpdateDigest(
} }
SerializationBuffer().Grow(SerializationBuffer().size() << 1); SerializationBuffer().Grow(SerializationBuffer().size() << 1);
} }
digest_ ^= IdentifiabilityDigestOfBytes(base::as_bytes( builder_.AddAtomic(base::as_bytes(
base::make_span(SerializationBuffer().data(), serialized_size))); base::make_span(SerializationBuffer().data(), serialized_size)));
total_ops_digested_++; total_ops_digested_++;
cur_ops_digested++; cur_ops_digested++;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "cc/paint/draw_image.h" #include "cc/paint/draw_image.h"
#include "cc/paint/image_provider.h" #include "cc/paint/image_provider.h"
#include "cc/paint/paint_cache.h" #include "cc/paint/paint_cache.h"
#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
#include "third_party/blink/renderer/platform/geometry/int_size.h" #include "third_party/blink/renderer/platform/geometry/int_size.h"
#include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/skia/include/utils/SkNoDrawCanvas.h" #include "third_party/skia/include/utils/SkNoDrawCanvas.h"
...@@ -46,8 +47,8 @@ class PLATFORM_EXPORT IdentifiabilityPaintOpDigest { ...@@ -46,8 +47,8 @@ class PLATFORM_EXPORT IdentifiabilityPaintOpDigest {
prefix_skip_count_ = prefix_skip_count; prefix_skip_count_ = prefix_skip_count;
} }
// The digest that was calculated, based on the PaintOps observed. // The IdentifiabilityToken (digest), based on the PaintOps observed.
uint64_t digest() const { return digest_; } IdentifiableToken GetToken() const { return builder_.GetToken(); }
bool encountered_partially_digested_image() const { bool encountered_partially_digested_image() const {
return encountered_partially_digested_image_; return encountered_partially_digested_image_;
...@@ -71,9 +72,8 @@ class PLATFORM_EXPORT IdentifiabilityPaintOpDigest { ...@@ -71,9 +72,8 @@ class PLATFORM_EXPORT IdentifiabilityPaintOpDigest {
// IdentifiabilityPaintOpDigest object. // IdentifiabilityPaintOpDigest object.
const int max_digest_ops_; const int max_digest_ops_;
// The current identifiability digest -- potentially updated every // Potentially updated every MaybeUpdateDigest() call.
// MaybeUpdateDigest() call. IdentifiableTokenBuilder builder_;
uint64_t digest_ = 0;
// The number of PaintOps that have contributed to the current digest -- used // The number of PaintOps that have contributed to the current digest -- used
// to stop updating the digest after a threshold number of operations to avoid // to stop updating the digest after a threshold number of operations to avoid
......
...@@ -48,7 +48,8 @@ class StudyParticipationRaii { ...@@ -48,7 +48,8 @@ class StudyParticipationRaii {
constexpr IntSize kSize(10, 10); constexpr IntSize kSize(10, 10);
constexpr float kScaleX = 1.0f, kScaleY = 1.0f; constexpr float kScaleX = 1.0f, kScaleY = 1.0f;
constexpr uint64_t kScaleDigest = UINT64_C(5461154373811575393); constexpr int64_t kScaleDigest = INT64_C(8258647715449129112);
constexpr int64_t kTokenBuilderInitialDigest = INT64_C(6544625333304541877);
TEST(IdentifiabilityPaintOpDigestTest, Construct) { TEST(IdentifiabilityPaintOpDigestTest, Construct) {
IdentifiabilityPaintOpDigest identifiability_paintop_digest(kSize); IdentifiabilityPaintOpDigest identifiability_paintop_digest(kSize);
...@@ -59,13 +60,14 @@ TEST(IdentifiabilityPaintOpDigestTest, Construct_InStudy) { ...@@ -59,13 +60,14 @@ TEST(IdentifiabilityPaintOpDigestTest, Construct_InStudy) {
IdentifiabilityPaintOpDigest identifiability_paintop_digest(kSize); IdentifiabilityPaintOpDigest identifiability_paintop_digest(kSize);
} }
TEST(IdentifiabilityPaintOpDigestTest, InitialDigestIsZero) { TEST(IdentifiabilityPaintOpDigestTest, InitialDigest) {
StudyParticipationRaii study_participation_raii; StudyParticipationRaii study_participation_raii;
IdentifiabilityPaintOpDigest identifiability_paintop_digest(kSize); IdentifiabilityPaintOpDigest identifiability_paintop_digest(kSize);
auto paint_record = sk_make_sp<cc::PaintRecord>(); auto paint_record = sk_make_sp<cc::PaintRecord>();
identifiability_paintop_digest.MaybeUpdateDigest(paint_record, identifiability_paintop_digest.MaybeUpdateDigest(paint_record,
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
EXPECT_EQ(UINT64_C(0), identifiability_paintop_digest.digest()); EXPECT_EQ(kTokenBuilderInitialDigest,
identifiability_paintop_digest.GetToken().ToUkmMetricValue());
EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops()); EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops());
EXPECT_FALSE( EXPECT_FALSE(
...@@ -79,20 +81,22 @@ TEST(IdentifiabilityPaintOpDigestTest, SimpleDigest) { ...@@ -79,20 +81,22 @@ TEST(IdentifiabilityPaintOpDigestTest, SimpleDigest) {
paint_record->push<cc::ScaleOp>(kScaleX, kScaleY); paint_record->push<cc::ScaleOp>(kScaleX, kScaleY);
identifiability_paintop_digest.MaybeUpdateDigest(paint_record, identifiability_paintop_digest.MaybeUpdateDigest(paint_record,
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
EXPECT_EQ(kScaleDigest, identifiability_paintop_digest.digest()); EXPECT_EQ(kScaleDigest,
identifiability_paintop_digest.GetToken().ToUkmMetricValue());
EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops()); EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops());
EXPECT_FALSE( EXPECT_FALSE(
identifiability_paintop_digest.encountered_partially_digested_image()); identifiability_paintop_digest.encountered_partially_digested_image());
} }
TEST(IdentifiabilityPaintOpDigestTest, DigestIsZeroIfNotInStudy) { TEST(IdentifiabilityPaintOpDigestTest, DigestIsInitialIfNotInStudy) {
IdentifiabilityPaintOpDigest identifiability_paintop_digest(kSize); IdentifiabilityPaintOpDigest identifiability_paintop_digest(kSize);
auto paint_record = sk_make_sp<cc::PaintRecord>(); auto paint_record = sk_make_sp<cc::PaintRecord>();
paint_record->push<cc::ScaleOp>(1.0f, 1.0f); paint_record->push<cc::ScaleOp>(1.0f, 1.0f);
identifiability_paintop_digest.MaybeUpdateDigest(paint_record, identifiability_paintop_digest.MaybeUpdateDigest(paint_record,
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
EXPECT_EQ(UINT64_C(0), identifiability_paintop_digest.digest()); EXPECT_EQ(kTokenBuilderInitialDigest,
identifiability_paintop_digest.GetToken().ToUkmMetricValue());
EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops()); EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops());
EXPECT_FALSE( EXPECT_FALSE(
...@@ -108,7 +112,8 @@ TEST(IdentifiabilityPaintOpDigestTest, SkipsTextOps) { ...@@ -108,7 +112,8 @@ TEST(IdentifiabilityPaintOpDigestTest, SkipsTextOps) {
1.0f, 1.0f, cc::PaintFlags()); 1.0f, 1.0f, cc::PaintFlags());
identifiability_paintop_digest.MaybeUpdateDigest(paint_record, identifiability_paintop_digest.MaybeUpdateDigest(paint_record,
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
EXPECT_EQ(UINT64_C(0), identifiability_paintop_digest.digest()); EXPECT_EQ(kTokenBuilderInitialDigest,
identifiability_paintop_digest.GetToken().ToUkmMetricValue());
EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops()); EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops());
EXPECT_FALSE( EXPECT_FALSE(
...@@ -135,10 +140,10 @@ TEST(IdentifiabilityPaintOpDigestTest, SkPathDigestStability) { ...@@ -135,10 +140,10 @@ TEST(IdentifiabilityPaintOpDigestTest, SkPathDigestStability) {
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
identifiability_paintop_digest2.MaybeUpdateDigest(paint_record2, identifiability_paintop_digest2.MaybeUpdateDigest(paint_record2,
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
EXPECT_EQ(identifiability_paintop_digest1.digest(), EXPECT_EQ(identifiability_paintop_digest1.GetToken().ToUkmMetricValue(),
identifiability_paintop_digest2.digest()); identifiability_paintop_digest2.GetToken().ToUkmMetricValue());
EXPECT_EQ(UINT64_C(154630961637231072), EXPECT_EQ(INT64_C(-1093634256342000670),
identifiability_paintop_digest1.digest()); identifiability_paintop_digest1.GetToken().ToUkmMetricValue());
EXPECT_FALSE(identifiability_paintop_digest1.encountered_skipped_ops()); EXPECT_FALSE(identifiability_paintop_digest1.encountered_skipped_ops());
EXPECT_FALSE( EXPECT_FALSE(
...@@ -174,10 +179,10 @@ TEST(IdentifiabilityPaintOpDigestTest, PaintShaderStability) { ...@@ -174,10 +179,10 @@ TEST(IdentifiabilityPaintOpDigestTest, PaintShaderStability) {
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
identifiability_paintop_digest2.MaybeUpdateDigest(paint_record2, identifiability_paintop_digest2.MaybeUpdateDigest(paint_record2,
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
EXPECT_EQ(identifiability_paintop_digest1.digest(), EXPECT_EQ(identifiability_paintop_digest1.GetToken().ToUkmMetricValue(),
identifiability_paintop_digest2.digest()); identifiability_paintop_digest2.GetToken().ToUkmMetricValue());
EXPECT_EQ(UINT64_C(4893847605848349986), EXPECT_EQ(INT64_C(6157094048912696853),
identifiability_paintop_digest1.digest()); identifiability_paintop_digest1.GetToken().ToUkmMetricValue());
} }
TEST(IdentifiabilityPaintOpDigestTest, BufferLeftoversDontAffectFutureDigests) { TEST(IdentifiabilityPaintOpDigestTest, BufferLeftoversDontAffectFutureDigests) {
...@@ -201,9 +206,10 @@ TEST(IdentifiabilityPaintOpDigestTest, BufferLeftoversDontAffectFutureDigests) { ...@@ -201,9 +206,10 @@ TEST(IdentifiabilityPaintOpDigestTest, BufferLeftoversDontAffectFutureDigests) {
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
identifiability_paintop_digest2.MaybeUpdateDigest(paint_record2, identifiability_paintop_digest2.MaybeUpdateDigest(paint_record2,
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
EXPECT_EQ(UINT64_C(15080511244712756058), EXPECT_EQ(INT64_C(-1855817800596177722),
identifiability_paintop_digest1.digest()); identifiability_paintop_digest1.GetToken().ToUkmMetricValue());
EXPECT_EQ(kScaleDigest, identifiability_paintop_digest2.digest()); EXPECT_EQ(kScaleDigest,
identifiability_paintop_digest2.GetToken().ToUkmMetricValue());
EXPECT_FALSE(identifiability_paintop_digest1.encountered_skipped_ops()); EXPECT_FALSE(identifiability_paintop_digest1.encountered_skipped_ops());
EXPECT_FALSE( EXPECT_FALSE(
...@@ -231,8 +237,8 @@ TEST(IdentifiabilityPaintOpDigestTest, ...@@ -231,8 +237,8 @@ TEST(IdentifiabilityPaintOpDigestTest,
paint_record->push<cc::ScaleOp>(kScaleX, kScaleY); paint_record->push<cc::ScaleOp>(kScaleX, kScaleY);
identifiability_paintop_digest.MaybeUpdateDigest(paint_record, identifiability_paintop_digest.MaybeUpdateDigest(paint_record,
/*num_ops_to_visit=*/2); /*num_ops_to_visit=*/2);
EXPECT_EQ(UINT64_C(11133276391926094139), EXPECT_EQ(INT64_C(-2635322358402873102),
identifiability_paintop_digest.digest()); identifiability_paintop_digest.GetToken().ToUkmMetricValue());
EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops()); EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops());
EXPECT_FALSE( EXPECT_FALSE(
...@@ -253,7 +259,8 @@ TEST(IdentifiabilityPaintOpDigestTest, IgnoresPrefixAndSuffix) { ...@@ -253,7 +259,8 @@ TEST(IdentifiabilityPaintOpDigestTest, IgnoresPrefixAndSuffix) {
identifiability_paintop_digest.SetPrefixSkipCount(1); identifiability_paintop_digest.SetPrefixSkipCount(1);
identifiability_paintop_digest.MaybeUpdateDigest(paint_record, identifiability_paintop_digest.MaybeUpdateDigest(paint_record,
/*num_ops_to_visit=*/2); /*num_ops_to_visit=*/2);
EXPECT_EQ(kScaleDigest, identifiability_paintop_digest.digest()); EXPECT_EQ(kScaleDigest,
identifiability_paintop_digest.GetToken().ToUkmMetricValue());
EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops()); EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops());
EXPECT_FALSE( EXPECT_FALSE(
...@@ -277,8 +284,8 @@ TEST(IdentifiabilityPaintOpDigestTest, IgnoresPrefixAndSuffix_MultipleOps) { ...@@ -277,8 +284,8 @@ TEST(IdentifiabilityPaintOpDigestTest, IgnoresPrefixAndSuffix_MultipleOps) {
identifiability_paintop_digest.SetPrefixSkipCount(1); identifiability_paintop_digest.SetPrefixSkipCount(1);
identifiability_paintop_digest.MaybeUpdateDigest(paint_record, identifiability_paintop_digest.MaybeUpdateDigest(paint_record,
/*num_ops_to_visit=*/2); /*num_ops_to_visit=*/2);
EXPECT_EQ(UINT64_C(5461154373811575393), EXPECT_EQ(INT64_C(8258647715449129112),
identifiability_paintop_digest.digest()); identifiability_paintop_digest.GetToken().ToUkmMetricValue());
EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops()); EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops());
EXPECT_FALSE( EXPECT_FALSE(
...@@ -294,7 +301,8 @@ TEST(IdentifiabilityPaintOpDigestTest, RecursesIntoDrawRecords) { ...@@ -294,7 +301,8 @@ TEST(IdentifiabilityPaintOpDigestTest, RecursesIntoDrawRecords) {
paint_record_outer->push<cc::DrawRecordOp>(paint_record_inner); paint_record_outer->push<cc::DrawRecordOp>(paint_record_inner);
identifiability_paintop_digest.MaybeUpdateDigest(paint_record_outer, identifiability_paintop_digest.MaybeUpdateDigest(paint_record_outer,
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
EXPECT_EQ(kScaleDigest, identifiability_paintop_digest.digest()); EXPECT_EQ(kScaleDigest,
identifiability_paintop_digest.GetToken().ToUkmMetricValue());
EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops()); EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops());
EXPECT_FALSE( EXPECT_FALSE(
...@@ -312,7 +320,8 @@ TEST(IdentifiabilityPaintOpDigestTest, RecursesIntoDrawRecords_TwoLevels) { ...@@ -312,7 +320,8 @@ TEST(IdentifiabilityPaintOpDigestTest, RecursesIntoDrawRecords_TwoLevels) {
paint_record_outer->push<cc::DrawRecordOp>(paint_record_middle); paint_record_outer->push<cc::DrawRecordOp>(paint_record_middle);
identifiability_paintop_digest.MaybeUpdateDigest(paint_record_outer, identifiability_paintop_digest.MaybeUpdateDigest(paint_record_outer,
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
EXPECT_EQ(kScaleDigest, identifiability_paintop_digest.digest()); EXPECT_EQ(kScaleDigest,
identifiability_paintop_digest.GetToken().ToUkmMetricValue());
EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops()); EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops());
EXPECT_FALSE( EXPECT_FALSE(
...@@ -324,21 +333,24 @@ TEST(IdentifiabilityPaintOpDigestTest, StopsUpdatingDigestAfterThreshold) { ...@@ -324,21 +333,24 @@ TEST(IdentifiabilityPaintOpDigestTest, StopsUpdatingDigestAfterThreshold) {
constexpr int kMaxOperations = 5; constexpr int kMaxOperations = 5;
IdentifiabilityPaintOpDigest identifiability_paintop_digest(kSize, IdentifiabilityPaintOpDigest identifiability_paintop_digest(kSize,
kMaxOperations); kMaxOperations);
uint64_t last_digest = UINT64_C(0); int64_t last_digest = INT64_C(0);
for (int i = 0; i < kMaxOperations; i++) { for (int i = 0; i < kMaxOperations; i++) {
auto paint_record = sk_make_sp<cc::PaintRecord>(); auto paint_record = sk_make_sp<cc::PaintRecord>();
paint_record->push<cc::ScaleOp>(kScaleX, kScaleY); paint_record->push<cc::ScaleOp>(kScaleX, kScaleY);
identifiability_paintop_digest.MaybeUpdateDigest(paint_record, identifiability_paintop_digest.MaybeUpdateDigest(paint_record,
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
EXPECT_NE(last_digest, identifiability_paintop_digest.digest()) << i; EXPECT_NE(last_digest,
last_digest = identifiability_paintop_digest.digest(); identifiability_paintop_digest.GetToken().ToUkmMetricValue())
<< i;
last_digest = identifiability_paintop_digest.GetToken().ToUkmMetricValue();
} }
auto paint_record = sk_make_sp<cc::PaintRecord>(); auto paint_record = sk_make_sp<cc::PaintRecord>();
paint_record->push<cc::ScaleOp>(kScaleX, kScaleY); paint_record->push<cc::ScaleOp>(kScaleX, kScaleY);
identifiability_paintop_digest.MaybeUpdateDigest(paint_record, identifiability_paintop_digest.MaybeUpdateDigest(paint_record,
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
EXPECT_EQ(last_digest, identifiability_paintop_digest.digest()); EXPECT_EQ(last_digest,
identifiability_paintop_digest.GetToken().ToUkmMetricValue());
EXPECT_TRUE(identifiability_paintop_digest.encountered_skipped_ops()); EXPECT_TRUE(identifiability_paintop_digest.encountered_skipped_ops());
EXPECT_FALSE( EXPECT_FALSE(
...@@ -357,7 +369,8 @@ TEST(IdentifiabilityPaintOpDigestTest, MassiveOpSkipped) { ...@@ -357,7 +369,8 @@ TEST(IdentifiabilityPaintOpDigestTest, MassiveOpSkipped) {
paint_record->push<cc::DrawPathOp>(path, cc::PaintFlags()); paint_record->push<cc::DrawPathOp>(path, cc::PaintFlags());
identifiability_paintop_digest.MaybeUpdateDigest(paint_record, identifiability_paintop_digest.MaybeUpdateDigest(paint_record,
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
EXPECT_EQ(UINT64_C(0), identifiability_paintop_digest.digest()); EXPECT_EQ(kTokenBuilderInitialDigest,
identifiability_paintop_digest.GetToken().ToUkmMetricValue());
EXPECT_TRUE(identifiability_paintop_digest.encountered_skipped_ops()); EXPECT_TRUE(identifiability_paintop_digest.encountered_skipped_ops());
EXPECT_FALSE( EXPECT_FALSE(
...@@ -373,8 +386,8 @@ TEST(IdentifiabilityPaintOpDigestTest, DigestImageOp) { ...@@ -373,8 +386,8 @@ TEST(IdentifiabilityPaintOpDigestTest, DigestImageOp) {
nullptr); nullptr);
identifiability_paintop_digest.MaybeUpdateDigest(paint_record, identifiability_paintop_digest.MaybeUpdateDigest(paint_record,
/*num_ops_to_visit=*/1); /*num_ops_to_visit=*/1);
EXPECT_EQ(UINT64_C(17562263210018091295), EXPECT_EQ(INT64_C(72317288461381383),
identifiability_paintop_digest.digest()); identifiability_paintop_digest.GetToken().ToUkmMetricValue());
EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops()); EXPECT_FALSE(identifiability_paintop_digest.encountered_skipped_ops());
EXPECT_TRUE( EXPECT_TRUE(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment