Commit 9a5409a0 authored by Asanka Herath's avatar Asanka Herath Committed by Commit Bot

[privacy_budget] Use std::array instead of C style array.

Bug: 973801
Change-Id: I80eb6eace8fd62e52876cc8c437fdae0e9b2906a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2439494Reviewed-by: default avatarAsanka Herath <asanka@chromium.org>
Reviewed-by: default avatarAlex Turner <alexmt@chromium.org>
Commit-Queue: Asanka Herath <asanka@chromium.org>
Cr-Commit-Position: refs/heads/master@{#821592}
parent 0815dca2
...@@ -3,6 +3,11 @@ ...@@ -3,6 +3,11 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h" #include "third_party/blink/public/common/privacy_budget/identifiable_token_builder.h"
#include <algorithm>
#include <iterator>
#include <type_traits>
#include "base/check.h" #include "base/check.h"
#include "base/check_op.h" #include "base/check_op.h"
#include "base/hash/legacy_hash.h" #include "base/hash/legacy_hash.h"
...@@ -19,28 +24,35 @@ constexpr uint64_t kChainingValueSeed = UINT64_C(6544625333304541877); ...@@ -19,28 +24,35 @@ constexpr uint64_t kChainingValueSeed = UINT64_C(6544625333304541877);
const size_t IdentifiableTokenBuilder::kBlockSizeInBytes; const size_t IdentifiableTokenBuilder::kBlockSizeInBytes;
IdentifiableTokenBuilder::IdentifiableTokenBuilder() IdentifiableTokenBuilder::IdentifiableTokenBuilder()
: partial_size_(0), chaining_value_(kChainingValueSeed) {} : chaining_value_(kChainingValueSeed) {
// Ensures that BlockBuffer iterators are random-access on all platforms.
static_assert(
std::is_same<std::random_access_iterator_tag,
std::iterator_traits<
BlockBuffer::iterator>::iterator_category>::value,
"Iterator operations may not be constant time.");
}
IdentifiableTokenBuilder::IdentifiableTokenBuilder( IdentifiableTokenBuilder::IdentifiableTokenBuilder(
const IdentifiableTokenBuilder& other) { const IdentifiableTokenBuilder& other) {
partial_size_ = other.partial_size_; partial_ = other.partial_;
position_ = partial_.begin();
std::advance(position_, other.PartialSize());
chaining_value_ = other.chaining_value_; chaining_value_ = other.chaining_value_;
memcpy(partial_, other.partial_, partial_size_);
} }
IdentifiableTokenBuilder::IdentifiableTokenBuilder(ByteBuffer buffer) IdentifiableTokenBuilder::IdentifiableTokenBuilder(ByteSpan buffer)
: IdentifiableTokenBuilder() { : IdentifiableTokenBuilder() {
AddBytes(buffer); AddBytes(buffer);
} }
IdentifiableTokenBuilder& IdentifiableTokenBuilder::AddBytes( IdentifiableTokenBuilder& IdentifiableTokenBuilder::AddBytes(ByteSpan message) {
ByteBuffer message) { DCHECK_NE(position_, partial_.end());
DCHECK_LE(partial_size_, kBlockSizeInBytes);
// Phase 1: // Phase 1:
// Slurp in as much of the message as necessary if there's a partial block // Slurp in as much of the message as necessary if there's a partial block
// already assembled. Copying is expensive, so |partial_| is only involved // already assembled. Copying is expensive, so |partial_| is only involved
// when there's some left over bytes from a prior round. // when there's some left over bytes from a prior round.
if (partial_size_ > 0 && !message.empty()) if (partial_.begin() != position_ && !message.empty())
message = SkimIntoPartial(message); message = SkimIntoPartial(message);
if (message.empty()) if (message.empty())
...@@ -48,7 +60,7 @@ IdentifiableTokenBuilder& IdentifiableTokenBuilder::AddBytes( ...@@ -48,7 +60,7 @@ IdentifiableTokenBuilder& IdentifiableTokenBuilder::AddBytes(
// Phase 2: // Phase 2:
// Consume as many full blocks as possible from |message|. // Consume as many full blocks as possible from |message|.
DCHECK_EQ(partial_size_, 0u); DCHECK_EQ(position_, partial_.begin());
while (message.size() >= kBlockSizeInBytes) { while (message.size() >= kBlockSizeInBytes) {
DigestBlock(message.first<kBlockSizeInBytes>()); DigestBlock(message.first<kBlockSizeInBytes>());
message = message.subspan(kBlockSizeInBytes); message = message.subspan(kBlockSizeInBytes);
...@@ -63,8 +75,7 @@ IdentifiableTokenBuilder& IdentifiableTokenBuilder::AddBytes( ...@@ -63,8 +75,7 @@ IdentifiableTokenBuilder& IdentifiableTokenBuilder::AddBytes(
return *this; return *this;
} }
IdentifiableTokenBuilder& IdentifiableTokenBuilder::AddAtomic( IdentifiableTokenBuilder& IdentifiableTokenBuilder::AddAtomic(ByteSpan buffer) {
ByteBuffer buffer) {
AlignPartialBuffer(); AlignPartialBuffer();
AddValue(buffer.size_bytes()); AddValue(buffer.size_bytes());
AddBytes(buffer); AddBytes(buffer);
...@@ -82,45 +93,42 @@ IdentifiableTokenBuilder::operator IdentifiableToken() const { ...@@ -82,45 +93,42 @@ IdentifiableTokenBuilder::operator IdentifiableToken() const {
} }
IdentifiableToken IdentifiableTokenBuilder::GetToken() const { IdentifiableToken IdentifiableTokenBuilder::GetToken() const {
if (partial_size_ == 0) if (position_ == partial_.begin())
return chaining_value_; return chaining_value_;
return IdentifiableToken( return IdentifiableToken(
base::legacy::CityHash64WithSeed(GetPartialBlock(), chaining_value_)); base::legacy::CityHash64WithSeed(GetPartialBlock(), chaining_value_));
} }
IdentifiableTokenBuilder::ByteBuffer IdentifiableTokenBuilder::SkimIntoPartial( IdentifiableTokenBuilder::ByteSpan IdentifiableTokenBuilder::SkimIntoPartial(
ByteBuffer message) { ByteSpan message) {
DCHECK(!message.empty() && partial_size_ < kBlockSizeInBytes); DCHECK(!message.empty() && position_ != partial_.end());
const auto to_copy = const auto to_copy = std::min<size_t>(
std::min(kBlockSizeInBytes - partial_size_, message.size()); std::distance(position_, partial_.end()), message.size());
memcpy(&partial_[partial_size_], message.data(), to_copy); position_ = std::copy_n(message.begin(), to_copy, position_);
partial_size_ += to_copy; if (position_ == partial_.end())
if (partial_size_ == kBlockSizeInBytes)
DigestBlock(TakeCompletedBlock()); DigestBlock(TakeCompletedBlock());
DCHECK_LE(partial_size_, kBlockSizeInBytes);
return message.subspan(to_copy); return message.subspan(to_copy);
} }
void IdentifiableTokenBuilder::AlignPartialBuffer() { void IdentifiableTokenBuilder::AlignPartialBuffer() {
const auto padding_to_add = const auto padding_to_add =
kBlockAlignment - (partial_size_ % kBlockAlignment); kBlockAlignment - (PartialSize() % kBlockAlignment);
if (padding_to_add == 0 || padding_to_add == kBlockAlignment) if (padding_to_add == kBlockAlignment)
return; return;
memset(partial_ + partial_size_, 0, padding_to_add); position_ = std::fill_n(position_, padding_to_add, 0);
partial_size_ += padding_to_add;
if (partial_size_ == kBlockSizeInBytes) if (position_ == partial_.end())
DigestBlock(TakeCompletedBlock()); DigestBlock(TakeCompletedBlock());
DCHECK_LT(partial_size_, sizeof(partial_)); DCHECK_NE(position_, partial_.end());
DCHECK(IsAligned()); DCHECK(IsAligned());
} }
void IdentifiableTokenBuilder::DigestBlock(FullBlock block) { void IdentifiableTokenBuilder::DigestBlock(ConstFullBlockSpan block) {
// partial_ should've been flushed before calling this. // partial_ should've been flushed before calling this.
DCHECK_EQ(partial_size_, 0u); DCHECK_EQ(position_, partial_.begin());
// The chaining value (initialized with the initialization vector // The chaining value (initialized with the initialization vector
// kChainingValueSeed) is only used for diffusion. There's no length padding // kChainingValueSeed) is only used for diffusion. There's no length padding
...@@ -133,12 +141,26 @@ void IdentifiableTokenBuilder::DigestBlock(FullBlock block) { ...@@ -133,12 +141,26 @@ void IdentifiableTokenBuilder::DigestBlock(FullBlock block) {
base::legacy::CityHash64WithSeed(base::make_span(block), chaining_value_); base::legacy::CityHash64WithSeed(base::make_span(block), chaining_value_);
} }
IdentifiableTokenBuilder::FullBlock size_t IdentifiableTokenBuilder::PartialSize() const {
return std::distance<BlockBuffer::const_iterator>(partial_.begin(),
position_);
}
IdentifiableTokenBuilder::ConstFullBlockSpan
IdentifiableTokenBuilder::TakeCompletedBlock() { IdentifiableTokenBuilder::TakeCompletedBlock() {
DCHECK_EQ(partial_size_, kBlockSizeInBytes); DCHECK_EQ(position_, partial_.end());
auto buffer = base::make_span(partial_); auto buffer = base::make_span(partial_);
partial_size_ = 0; position_ = partial_.begin();
return buffer; return buffer;
} }
bool IdentifiableTokenBuilder::IsAligned() const {
return PartialSize() % kBlockAlignment == 0;
}
IdentifiableTokenBuilder::ByteSpan IdentifiableTokenBuilder::GetPartialBlock()
const {
return ByteSpan(partial_.begin(), position_);
}
} // namespace blink } // namespace blink
...@@ -39,7 +39,7 @@ IdentifiabilityDigestOfBytes(base::span<const uint8_t> in); ...@@ -39,7 +39,7 @@ IdentifiabilityDigestOfBytes(base::span<const uint8_t> in);
// The zero-length digest, i.e. the digest computed for no bytes. // The zero-length digest, i.e. the digest computed for no bytes.
static constexpr uint64_t kIdentifiabilityDigestOfNoBytes = static constexpr uint64_t kIdentifiabilityDigestOfNoBytes =
0x9ae16a3b2f90404fULL; UINT64_C(0x9ae16a3b2f90404f);
} // namespace blink } // namespace blink
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABLE_TOKEN_BUILDER_H_ #ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABLE_TOKEN_BUILDER_H_
#define THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABLE_TOKEN_BUILDER_H_ #define THIRD_PARTY_BLINK_PUBLIC_COMMON_PRIVACY_BUDGET_IDENTIFIABLE_TOKEN_BUILDER_H_
#include <array>
#include "base/containers/span.h" #include "base/containers/span.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/sys_byteorder.h" #include "base/sys_byteorder.h"
...@@ -40,7 +42,7 @@ namespace blink { ...@@ -40,7 +42,7 @@ namespace blink {
class BLINK_COMMON_EXPORT IdentifiableTokenBuilder { class BLINK_COMMON_EXPORT IdentifiableTokenBuilder {
public: public:
// Convenient alias for a span of const uint8_t. // Convenient alias for a span of const uint8_t.
using ByteBuffer = base::span<const uint8_t>; using ByteSpan = IdentifiableToken::ByteSpan;
// Initializes an "empty" incremental digest for the purpose of constructing // Initializes an "empty" incremental digest for the purpose of constructing
// an identifiability sample. // an identifiability sample.
...@@ -48,13 +50,13 @@ class BLINK_COMMON_EXPORT IdentifiableTokenBuilder { ...@@ -48,13 +50,13 @@ class BLINK_COMMON_EXPORT IdentifiableTokenBuilder {
// Initializes an incremental digest and populates it with the data contained // Initializes an incremental digest and populates it with the data contained
// in |message|. // in |message|.
explicit IdentifiableTokenBuilder(ByteBuffer message); explicit IdentifiableTokenBuilder(ByteSpan message);
// Copies the intermediate state. // Copies the intermediate state.
IdentifiableTokenBuilder(const IdentifiableTokenBuilder&); IdentifiableTokenBuilder(const IdentifiableTokenBuilder&);
// Feeds data contained in |buffer| to the digest. // Feeds data contained in |buffer| to the digest.
IdentifiableTokenBuilder& AddBytes(ByteBuffer buffer); IdentifiableTokenBuilder& AddBytes(ByteSpan buffer);
// Feeds data contained in |buffer| to the digest, but precedes the buffer // Feeds data contained in |buffer| to the digest, but precedes the buffer
// contents with an integer indicating the length. Use this when: // contents with an integer indicating the length. Use this when:
...@@ -73,7 +75,7 @@ class BLINK_COMMON_EXPORT IdentifiableTokenBuilder { ...@@ -73,7 +75,7 @@ class BLINK_COMMON_EXPORT IdentifiableTokenBuilder {
// memory, then consider adding a length directly via AddValue() prior to // memory, then consider adding a length directly via AddValue() prior to
// adding the contents of the buffer. Doing so will achieve the same ends as // adding the contents of the buffer. Doing so will achieve the same ends as
// AddAtomic(). // AddAtomic().
IdentifiableTokenBuilder& AddAtomic(ByteBuffer buffer); IdentifiableTokenBuilder& AddAtomic(ByteSpan buffer);
IdentifiableTokenBuilder& AddAtomic(base::StringPiece string) { IdentifiableTokenBuilder& AddAtomic(base::StringPiece string) {
return AddAtomic(base::as_bytes(base::make_span(string))); return AddAtomic(base::as_bytes(base::make_span(string)));
} }
...@@ -135,12 +137,15 @@ class BLINK_COMMON_EXPORT IdentifiableTokenBuilder { ...@@ -135,12 +137,15 @@ class BLINK_COMMON_EXPORT IdentifiableTokenBuilder {
// must always stay constant across platforms. // must always stay constant across platforms.
static constexpr size_t kBlockAlignment = 8; static constexpr size_t kBlockAlignment = 8;
// A span of exactly |kBlockSizeInBytes| bytes. // An array of exactly |kBlockSizeInBytes| bytes.
using FullBlock = base::span<const uint8_t, kBlockSizeInBytes>; using BlockBuffer = std::array<uint8_t, kBlockSizeInBytes>;
// A view of a full block.
using ConstFullBlockSpan = base::span<const uint8_t, kBlockSizeInBytes>;
// Returns true if the partial buffer is aligned on |kBlockAlignment| // Returns true if the partial buffer is aligned on |kBlockAlignment|
// boundary. // boundary.
bool IsAligned() const { return partial_size_ % kBlockAlignment == 0; } bool IsAligned() const;
// Appends enough NUL bytes to |partial_| until the next insertion point is // Appends enough NUL bytes to |partial_| until the next insertion point is
// aligned on a |kBlockAlignment| boundary. // aligned on a |kBlockAlignment| boundary.
...@@ -154,21 +159,19 @@ class BLINK_COMMON_EXPORT IdentifiableTokenBuilder { ...@@ -154,21 +159,19 @@ class BLINK_COMMON_EXPORT IdentifiableTokenBuilder {
// Captures the |kBlockSizeInBytes| bytes of data in |block| into the digest. // Captures the |kBlockSizeInBytes| bytes of data in |block| into the digest.
// |block| must be exactly this many bytes. // |block| must be exactly this many bytes.
void DigestBlock(FullBlock block); void DigestBlock(ConstFullBlockSpan block);
// Captures as many bytes as possible from |message| into the partial block in // Captures as many bytes as possible from |message| into the partial block in
// |partial_|. It captures a maximum of |kBlockSizeInBytes - 1| bytes. // |partial_|. It captures a maximum of |kBlockSizeInBytes - 1| bytes.
// //
// Returns a span covering the remainder of |message| that was not consumed. // Returns a span covering the remainder of |message| that was not consumed.
ByteBuffer SkimIntoPartial(ByteBuffer message); ByteSpan SkimIntoPartial(ByteSpan message);
// Returns a span for the contents of the partial block. // Returns a span for the contents of the partial block.
// //
// Can be called at any point. Does not change the state of the partial // Can be called at any point. Does not change the state of the partial
// buffer. // buffer.
ByteBuffer GetPartialBlock() const { ByteSpan GetPartialBlock() const;
return base::make_span(&partial_[0], partial_size_);
}
// Returns a span that includes the contents of the partial block and backed // Returns a span that includes the contents of the partial block and backed
// by |partial_|. // by |partial_|.
...@@ -178,13 +181,17 @@ class BLINK_COMMON_EXPORT IdentifiableTokenBuilder { ...@@ -178,13 +181,17 @@ class BLINK_COMMON_EXPORT IdentifiableTokenBuilder {
// //
// NOTE: Any subsequent AddBytes(), AddValue(), AddAtomic() calls will // NOTE: Any subsequent AddBytes(), AddValue(), AddAtomic() calls will
// invalidate the returned FullBlock. // invalidate the returned FullBlock.
FullBlock TakeCompletedBlock(); ConstFullBlockSpan TakeCompletedBlock();
// Size of partially filled buffer.
size_t PartialSize() const;
// Accumulates smaller pieces of data until we have a full block. // Accumulates smaller pieces of data until we have a full block.
alignas(int64_t) uint8_t partial_[kBlockSizeInBytes]; alignas(int64_t) BlockBuffer partial_;
// Count of bytes in |partial_|. // Next available position in `partial_`. std::array iterators are never
size_t partial_size_; // invalidated.
BlockBuffer::iterator position_ = partial_.begin();
// Merkle-Damgård chaining. // Merkle-Damgård chaining.
uint64_t chaining_value_; uint64_t chaining_value_;
......
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