coding: utf-8
title: Protected Audience Key Value Services abbrev: "KV Services" docname: draft-ietf-protected-audience-key-value-services-latest category: std submissionType: IETF
area: TBD workgroup: TBD keyword: Internet-Draft
ipr: trust200902
stand_alone: yes pi: [toc, sortrefs, symrefs]
name: Peiwen Hu
organization: Google
email: [email protected]
- name: Tianyang Xu organization: Google email: [email protected]
- name: Lusa Zhan organization: Google email: [email protected]
normative: HTTPS: RFC2818 CBOR: RFC8949 CDDL: RFC8610 JSON: RFC8259 OHTTP: RFC9458 HPKE: RFC9180 GZIP: RFC1952 Brotli: RFC7932
informative:
--- abstract
This document specifies a protocol for a Key Value Service that can serve data with low latency and no side effects. The data served can be used by clients for advertisement selection and the lack of side effects can be used to advance user privacy.
--- middle
Protected Audience is a privacy advancing API that serves remarketing and custom audiences use cases. Key Value Services are trusted execution environment (TEE) based Key/Value databases that can be used to store and integrate real-time data into Protected Audiences Auctions. The Protected Audience proposal leverages Key Value Services to incorporate real-time information into ad selection for both buyers and sellers. This information could be used, for example, to add budgeting data about each ad. These services provide a flexible mechanism for fetching and processing data. While event-level logging is explicitly prohibited, the services may have operational side effects like monitoring to ensure security and prevent abuse.
This document provides a specification for the request and response message format that a client can use to communicate with the Key Value Service as part of the client's implementation of the Protected Audience API.
This document does not describe distribution of private keys to the Key Value Service.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 {{!RFC2119}} {{!RFC8174}} when, and only when, they appear in all capitals, as shown here.
The key word "client" is to be interpreted as an implementation of this document that creates Requests ({{request}}) and consumes Responses ({{response}}). The key phrase "Key Value Service" is to be interpreted as an implementation of this document that consumes Requests and creates Responses.
To understand this document, it is important to know that the communication between the client and the remote services uses a request-response message exchange pattern. On a high level, these request and response messages adhere to the following communication protocol:
- Data is transmitted over [HTTPS] using the
POST
method. - Data within the request and response is encrypted with [HPKE].
- The core request and response data is encoded using [CBOR].
Requests MUST contain a cleartext HTTP Content-Type
header with
value message/ad-auction-trusted-signals-request
.
Responses MUST contain a cleartext HTTP Content-Type
header with
value message/ad-auction-trusted-signals-response
.
The Key Value Service uses [HPKE] with the following configuration for encryption:
- HPKE KEM ID (Key encapsulation mechanisms): 0x0020 DHKEM(X25519, HKDF-SHA256), see {{Section 1 of HPKE}}
- HPKE KDF ID (key derivation functions): 0x0001 HKDF-SHA256, see {{Section 7.2 of HPKE}}
- HPKE AEAD ID (Authenticated Encryption with Associated Data): AES-256-GCM, see {{Section 7.3 of HPKE}}
Before encryption and after decryption, the requests and responses have the following framing:
Byte | 0 | 0 | 1 to 4 | 5 to Size+4 | Size+5 to end |
---|---|---|---|---|---|
Bits | 7-2 | 1-0 | * | * | * |
-------- | --------- | ------------- | -------- | ----------------- | --------------- |
Contents | Unused | Compression | Size | Payload | Padding |
The request/response is framed with this 5 byte header.
The first byte is the format+compression byte. The lower 2 bits specify the format and compression ({{compression}}). The higher 6 bits are currently unused.
The following 4 bytes are the length of the request message in network byte order.
Padding is applied differently for request and response and will be discussed in the respective sections.
Compression | Description |
---|---|
0x00 | [CBOR], no compression |
0x01 | [CBOR], compressed in [Brotli] |
0x02 | [CBOR], compressed in [GZIP] |
0x03 | Reserved |
Requests are always uncompressed so the Format+compression byte is 0x00.
For responses, the byte value depends on the acceptCompression
field
(see {{request-schema}}) in the request and the server behavior.
Requests are not compressed and have a tree-like hierarchy:
- Each request contains one or more partitions. Each partition is a collection of keys that SHALL be processed together by the service. Keys from separate partitions MUST NOT be processed together by the service.
- Each partition contains one or more key groups.
Each key group contains a list of
tags
set by the client. Each key group contains a list of keys to be looked up in the service's internal datastore. - Each partition has a unique identifier.
This allows the client to match the request partition with the corresponding
partitionOutput
(see {{compression-group}}) in the response. - Each partition has a compression group field. Results of partitions belonging to the same compression group can be compressed together in the response. The responses for different compression groups will be compressed separately in the response (see {{compression-group}}). Compressing the different groups separately avoids leaking the similarity of responses for different groups.
The request is encrypted with [HPKE] with the configuration specified at {{encryption}}.
The request uses a similar encapsulated message format to that used by [OHTTP].
Encapsulated Request {
Key Identifier (8),
HPKE KEM ID (16),
HPKE KDF ID (16),
HPKE AEAD ID (16),
Encapsulated KEM Shared Secret (8 * Nenc),
HPKE-Protected Request (..),
}
The service uses a repurposed [OHTTP] encapsulation mechanism (see {{Section 4.6 of OHTTP}})
for which it defines a new message/ad-auction-trusted-signals-request
media type.
Request encapsulation is similar to {{Section 4.3 of OHTTP}}, only with the
message/ad-auction-trusted-signals-request
media type:
- Construct a message header (
hdr
) by concatenating the values of theKey Identifier
,HPKE KEM ID
,HPKE KDF ID
, andHPKE AEAD ID
in network byte order. - Build a sequence of bytes (
info
) by concatenating the ASCII-encoded string "message/ad-auction-trusted-signals-request", a zero byte, andhdr
. - Create a sending HPKE context by invoking
SetupBaseS()
(Section 5.1.1 of [HPKE]) with the public key of the receiverpkR
andinfo
. This yields the contextsctxt
and an encapsulation keyenc
. - Encrypt
request
by invoking theSeal()
method onsctxt
(Section 5.2 of [HPKE]) with empty associated dataaad
, yielding ciphertextct
. - Concatenate the values of
hdr
,enc
, andct
.
In pseudocode, this procedure is as follows:
hdr = concat(encode(1, key_id),
encode(2, kem_id),
encode(2, kdf_id),
encode(2, aead_id))
info = concat(encode_str("message/ad-auction-trusted-signals-request"),
encode(1, 0),
hdr)
enc, sctxt = SetupBaseS(pkR, info)
ct = sctxt.Seal("", request)
enc_request = concat(hdr, enc, ct)
The client needs to save sctxt
for decryption of the response (see {{response-encryption}}).
A Key Value Service endpoint decrypts this encapsulated message in a similar manner to [OHTTP] Section 4.3, or more explicitly as follows:
- Parse
enc_request
intokey_id
,kem_id
,kdf_id
,aead_id
,enc
, andct
. - Find the matching HPKE private key,
skR
, corresponding tokey_id
. If there is no matching key, return an error. - Build a sequence of bytes (
info
) by concatenating the ASCII-encoded string "message/ad-auction-trusted-signals-request"; a zero byte;key_id
as an 8-bit integer; pluskem_id
,kdf_id
, andaead_id
as three 16-bit integers. - Create a receiving HPKE context,
rctxt
, by invokingSetupBaseR()
(Section 5.1.1 of [HPKE]) withskR
,enc
, andinfo
. - Decrypt
ct
by invoking theOpen()
method onrctxt
(Section 5.2 of [HPKE]), with an empty associated dataaad
, yieldingrequest
and returning an error on failure.
In pseudocode, this procedure is as follows:
key_id, kem_id, kdf_id, aead_id, enc, ct = parse(enc_request)
if version != 0 then return error
info = concat(encode_str("message/ad-auction-trusted-signals-request"),
encode(1, 0),
encode(1, key_id),
encode(2, kem_id),
encode(2, kdf_id),
encode(2, aead_id))
rctxt = SetupBaseR(enc, skR, info)
request, error = rctxt.Open("", ct)
Key Value Services retain the HPKE context, rctxt
, so that it can
encapsulate a response.
The plaintext request message uses the framing described in {{framing}}.
Messages MAY be zero padded.
The request is a [CBOR] encoded message with the following [CDDL] schema:
compressionType = "none" / "gzip" / "brotli"
request = {
? acceptCompression: [1* compressionType],
; A list of supported response compression algorithms; must contain at least one of "none", "gzip", "brotli"
? metadata: requestMetadata,
; Metadata that applies for the request as a whole.
partitions: [1* partition],
; A list of partitions. Each must be processed independently. Accessible by user-defined functions.
}
requestMetadata = {
? hostname: tstr,
; The hostname of the top-level frame calling runAdAuction
}
partition = {
id: uint,
; Unique id of the partition in this request. Used by responses to refer to request partitions.
compressionGroupId: uint,
; Unique id of a compression group in this request. Only partitions belonging to the same compression group will be compressed together in the response
? metadata: partitionMetadata,
; Partition-level metadata.
arguments: [* requestArgument],
; One group of keys and common attributes about them
}
;Single partition object. A collection of keys that can be processed together.
partitionMetadata = {
? experimentGroupId: tstr,
? slotSize: tstr,
? allSlotsRequestedSizes: tstr,
}
requestArgument = {
? tags: [1* tstr],
; List of tags describing this group's attributes. These MAY be picked from the list of available tags in {{tags}}.
? data: [* tstr],
; List of keys to get values for.
}
Each key group is expected to have exactly one tag from the following list (with the exact capitalization):
Tag | Description |
---|---|
interestGroupNames | Names of interest groups in the encompassing partition. |
keys | "keys" represent the keys to be looked up from the service's internal datastore. |
renderURLs | "renderURLs" represent URLs for advertisements to be looked up from the service's internal datastore. |
adComponentRenderURLs | "adComponentRenderURLs" represent component URLs for advertisements to be looked up from the service's internal datastore. |
This section describes how the client MAY form and serialize request messages in order to fetch values from the Trusted Key Value server.
This algorithm takes as input:
- an [HPKE]
public key
. - a
key id
integer associated withpublic key
. - a
metadata
map for global configuration, where both keys and values are strings. - a
compression groups
, which is a list ofgroup
s, each with the following parameters: - a
compressionGroupId
integer identifier of this compression group. - a
partitions
, which is a list ofpartition
s belonging to this compression group. Eachpartition
has the following parameters:- an
id
integer identifier of this partition. - a
namespace
map whose keys are strings and values are list of strings. - a
metadata
map whose keys and values are strings.
- an
The output is an [HPKE] ciphertext encrypted request
and a context
request context
.
- Let
request map
be an empty map. - Let
partitions
be an empty array. - For each
group
incompression groups
: - For each
partition
ingroup
'spartitions
: 1. Letp
be an empty map. 1. Setp["compressionGroupId"]
togroup
'scompressionGroupId
. 1. Setp["id"]
topartition
'sid
. 1. Setp["metadata"]
topartition
'smetadata
. 1. Letarguments
be an empty array. 1. For eachtag
→value
inpartition
'snamespace
:- If
tag
is one of {{tags}}: - Let
argument
be an empty map. - Set
argument["tags"]
to [tag
]. - Set
argument["data"]
tovalue
. - Insert
argument
intoarguments
. 1. Setp["arguments"]
toarguments
. 1. Insertp
intopartitions
.
- If
- Set
request map["metadata"]
tometadata
. - Set
request map["partitions"]
topartitions
. - Set
request map["acceptCompression"]
to["none", "gzip"]
. - [CBOR] encode
request map
topayload
. - Create a
framed payload
, as described in {{framing}}:- Create a {{framing}} header
framing header
. - Set
framing header
'sCompression
to 1. - Set
framing header
'sSize
to the size ofpayload
. - Set
framed payload
to the concatenation offraming header
andpayload
. - Padding MAY be added to
framed payload
. - Return an empty
request
on failure of any of the previous steps.
- Create a {{framing}} header
- [HPKE] encrypt
framed payload
usingpublic key
andkey id
as in {{request-encryption}} to get the [HPKE] encrypted ciphertextrequest
and [HPKE] encryption contextrequest context
. - Return
request
andrequest context
.
This section describes how the Key Value Service MUST deserialize request messages from the client.
The algorithm takes as input a serialized request message from the client and a list of HPKE private keys (along with their corresponding key IDs).
The output is either an error sent back to the client, an empty message sent back to the client, or a request message the Key Value Service can consume along with an HPKE context.
- Let
encrypted request
be the request received from the client. - Let
error_msg
be an empty string. - Decrypt
encrypted request
by using the input private key corresponding tokey_id
as described in {{request-encryption}}, to get the decrypted message andrctxt
.- If decryption fails, return failure.
- Else, save the decrypted output as
framed request
and saverctxt
.
- Remove and extract the first 5 bytes from
framed request
as theframing header
(described in {{framing}}), removing them fromframed request
.- If the
framing header
'sCompression
field is not0x00
(no compression), return failure.
- If the
- Let
length
be equal to theframing header
'sSize
field. - If
length
is greater than the length of the remaining bytes inframed request
, return failure. - Take the first
length
remaining bytes inframed response
asdecodable request
, discarding the rest. - [CBOR] decode
decodable request
into the message represented in {{request-schema}}. Let this beprocessed request
.- If decoding fails, return failure.
- If no
partitions
are present, return failure. - Set
compressionGroupMap
to an empty map. - For each
partition
inpartitions
:- Let
partitionIds
be an empty list. - Set
partitionIds
tocompressionGroupMap[compression group id]
if the map entry exists. - Append
partition["id"]
topartitionIds
. - Set
compressionGroupMap[compression group id]
topartitionIds
.
- Let
- Return
processed request
,compressionGroupMap
, andrctxt
.
The response is an HPKE encrypted message sent as a Response to a Request, containing a framed top-level CBOR encoded payload that itself can contain multiple, possibly compressed, CBOR encoded messages.
The response uses a similar encapsulated response format to that used by [OHTTP].
Encapsulated Response {
Nonce (8 * max(Nn, Nk)),
AEAD-Protected Response (..),
}
The response uses the a similar encapsulated response format to that used by [OHTTP] (see
{{Section 4.4 of OHTTP}}), but with the custom message/ad-auction-trusted-signals-response
media type instead of message/bhttp response
:
- Export a secret (
secret
) fromcontext
, using the string "message/ad-auction-trusted-signals-response" as theexporter_context
parameter tocontext.Export
; see Section 5.3 of [HPKE]. The length of this secret ismax(Nn, Nk)
, whereNn
andNk
are the length of the AEAD key and nonce that are associated withcontext
. - Generate a random value of length
max(Nn, Nk)
bytes, calledresponse_nonce
. - Extract a pseudorandom key (
prk
) using theExtract
function provided by the KDF algorithm associated with context. Theikm
input to this function issecret
; thesalt
input is the concatenation ofenc
(fromenc_request
) andresponse_nonce
. - Use the
Expand
function provided by the same KDF to create an AEAD key,key
, of lengthNk
-- the length of the keys used by the AEAD associated withcontext
. Generatingaead_key
uses a label of "key". - Use the same
Expand
function to create a nonce,nonce
, of lengthNn
-- the length of the nonce used by the AEAD. Generatingaead_nonce
uses a label of "nonce". - Encrypt
response
, passing the AEAD functionSeal
the values ofaead_key
,aead_nonce
, an emptyaad
, and apt
input ofresponse
. This yieldsct
. - Concatenate
response_nonce
andct
, yielding an Encapsulated Response,enc_response
. Note thatresponse_nonce
is of fixed length, so there is no ambiguity in parsing eitherresponse_nonce
orct
.
In pseudocode, this procedure is as follows:
secret = context.Export("message/ad-auction-trusted-signals-response", max(Nn, Nk))
response_nonce = random(max(Nn, Nk))
salt = concat(enc, response_nonce)
prk = Extract(salt, secret)
aead_key = Expand(prk, "key", Nk)
aead_nonce = Expand(prk, "nonce", Nn)
ct = Seal(aead_key, aead_nonce, "", response)
enc_response = concat(response_nonce, ct)
Clients decrypt an Encapsulated Response by reversing this process. That is,
Clients first parse enc_response
into response_nonce
and ct
. Then, they
follow the same process to derive values for aead_key
and aead_nonce
, using
their sending HPKE context, sctxt
, as the HPKE context, context
.
The Client uses these values to decrypt ct
using the AEAD function Open
.
Decrypting might produce an error, as follows:
response, error = Open(aead_key, aead_nonce, "", ct)
The plaintext response message uses the framing described in {{framing}}.
Padding is applied with sizes as multiples of 2^n KBs ranging from 0 to 2MB. So the valid response
sizes will be [0, 128B, 256B, 512B, 1KB, 2KB, 4KB, 8KB, 16KB, 32KB, 64KB, 128KB, 256KB, 512KB, 1MB, 2MB]
.
If the response message is larger than 2MB, an error is returned.
The response MAY be compressed. The compression is applied independently to each compression group. That
means, the response object mainly contains a list of compressed blobs, each for one compression
group. Each blob is for outputs of one or more partitions, sharing the same compressionGroup
value
as specified in the request.
The response is a [CBOR] encoded message with the following [CDDL] schema:
response = {
? compressionGroups : [* compressionGroup]
}
compressionGroup = {
? compressionGroupId: uint,
; Partition outputs with the same `compressionGroupId` specified in the request
; are compressed together.
? ttl_ms: uint,
; Adtech-specified TTL for client-side caching. In milliseconds. Unset means no caching.
? content: bstrs
; Compressed CBOR binary string using the algorithm specified in the request
; For details see compressed response content schema below.
}
The content of each compressionGroup
is a serialized [CBOR] list of partition outputs. This object
contains actual key value results for partitions in the corresponding compression group. The
uncompressed, deserialized [CBOR] content has the following [CDDL] schema:
compressionGroup = [* partitionOutput]
; Array of PartitionOutput objects
partitionOutput = {
id: uint
; Unique id of the partition from the request
? keyGroupOutputs: [* keyGroupOutput]
}
keyGroupOutput = {
tags: [* tstr]
; List of tags describing this key group's attributes
? keyValues: {
; At least one key-value pair if present
* tstr => tstr
}
; One value to be returned in response for one key
; If a keyValues object exists, it must at least contain one key-value pair.
; If no key-value pair can be returned, the keyGroupOutput object should not be in the response
}
Structured keys are keys that the client is aware of and the client can use the response to do additional processing. The value of these keys must abide by the following schema for the client to successfully parse them.
Note that they must be serialized to string when stored as the value.
The schema below is defined following the spec by
https://json-schema.org. For values for keys
from the interestGroupNames
namespace, they must conform to the
following schema, prior to being
serialized to string.
{
"title": "tkv.response.v2.InterestGroupResponse",
"description": "Format for value of keys in groups tagged 'interestGroupNames'",
"type": "object",
"additionalProperties": false,
"properties": {
"priorityVector": {
"type": "object",
"patternProperties": {
".*": {
"description": "signals",
"type": "number"
}
}
},
"updateIfOlderThanMs": {
"description": "This optional field specifies that the interest group should be updated if the interest group hasn't been joined or updated in a duration of time exceeding `updateIfOlderThanMs` milliseconds. Updates that ended in failure, either parse or network failure, are not considered to increment the last update or join time. An `updateIfOlderThanMs` that's less than 10 minutes will be clamped to 10 minutes.",
"type": "unsigned integer"
}
}
}
The Key Value Service runs user-defined functions (UDF) as part of request handling
and response generation. User-Defined Functions (UDFs) are custom functions implemented by adtech that encapsulate adtech-specific business logic for processing partitions within the Key Value Service. These functions are executed within a sandboxed environment without network or disk access, but have read access to data loaded into the Key Value Service.
Each UDF receives a single partition
object from the client request as input. The output of a UDF is a partitionOutput
object that contains the results of processing the partition.
The below algorithm describes how the Key Value Service MAY generate a response to a request.
The input is a list of deterministically encoded CBOR partitionOutputs
in {{response-schema}} as well as
the compressionGroupMap
and the HPKE receiver, rctxt
, context saved in {{request-parsing}}.
Assume that this response is to a request that includes gzip
in acceptCompression
.
The output is a response
to be sent to a Client.
- Create an empty
payload
object, corresponding to {{response-schema}}. - Set
compression groups
to an empty list. - Set
partitionOutputMap
to an empty map. - For each
partitionOutput
in the list ofpartitionOutputs
:- Set
partitionOutputMap[partitionOutput["id"]]
topartitionOutput
.
- Set
- For each (
compression group id
,partition ids
) incompressionGroupMap
:- Create an empty
compression group
object, corresponding to {{compression-group}}. - Set
cbor partitions array
to an empty CBOR array. - For each
partition id
inpartition ids
:- Set
partition output
topartitionOutputMap[partition id]
.- On failure to find the
partition id
, continue.
- On failure to find the
- Append
partition output
tocbor partitions array
.
- Set
- Set
cbor serialized payload
to the CBOR serializedcbor partitions array
.- On serialization failure, continue.
- Set
compression group content
to the [GZIP] compressedcbor serialized payload
.- On failure, continue.
- Set
compression group["compressionGroupId"]
tocompression group id
- Set
compression group["content"]
tocompression group content
. - Add
compression group
tocompression groups
.
- Create an empty
- Set
payload["compressionGroups"]
tocompression groups
. - Create a framed payload, as described in {{framing}}:
- Create a
framing header
. - Set the
framing header
Compression
to one of 2. - Set the
framing header
Size
to the size ofcompressed payload
. - Let
framed payload
equal the result of prepending the framing header topayload
. - Padding MAY be added to
framed payload
. - Return an empty
response
on failure of any of the previous steps.
- Create a
- Let
response
equal the result of the encryption and encapsulation offramed payload
withrctxt
, as described in {{response-encryption}}. Return an emptyresponse
on failure. - Return
response
.
This section describes how a conforming Client MUST parse and validate a response from a Trusted Key Value service.
It takes as input the request context
, returned from
{{request-generate}}, and an encrypted response
, an array of bytes
from the Key Value Service generated by {{response-generate}}.
The output is a results
which is a list of result
with the following parameters:
index
, a tuple of an integer and an integer, records the compression group id and partition id.interestGroupNames
, null or a map, whose keys and values are strings.keys
, null or a map, whose keys and values are strings.renderURLs
, null or a map, whose keys and values are strings.adComponentRenderURLs
, null or a map, whose keys and values are strings.
- Use
request context
as the context to decryptencrypted response
and obtainframed response
, returning failure if decryption fails. - Remove and extract the first 5 bytes from
framed response
as the framing header (described in {{framing}}), removing them fromframed response
. - If
framing header
'sCompression
field is not 0 or 2, return failure. - Let
length
be equal to theframing header
'sSize
field. - If
length
is greater than the length of the remaining bytes inframed response
, return failure. - Take the first
length
remaining bytes inframed response
asserialized response
, discarding the rest. - [CBOR] decode the
serialized response
intoresponse
, returning failure if decoding fails. - If
response
is not a map, return failure. - If
response["compressionGroups"]
does not exist, or is not an array, return failure. - Let
results
be an empty array. - For each
group
inresponse["compressionGroups"]
:- If
group
is not a map, return failure. - If
group["content"]
does not exist, return failure. - Set
serialized content
to the result of decompressinggroup["content"]
according to the compression algorithm specified in theframing header
'sCompression
field, returning failure if decompression fails. - [CBOR] decode the
serialized content
intocontent
, returning failure if decoding fails. - If
content
is not an array, return failure. - For each
partition
incontent
:- If
partition
is not a map, return failure. - If
partition["keyGroupOutputs"]
does not exist, or is not an array, return failure. - Initialize an empty
result
. - For each
output
inpartition["keyGroupOutputs"]
:- If
output
is not a map, return failure. - If
output["tags"]
does not exist, or is not an array, return failure. - If
output["keyValues"]
does not exist or is not a map, return failure. - Let
key value
be an empty map. - For each
key
→value
inoutput["keyValues"]
:- If
key
is not a string, return failure. - If
value
is not a map, return failure. - If
value["value"]
does not exist, or is not a string, return failure. - Set
key value
[key
] tovalue["value"]
.
- If
- If
output["tags"]
equals to "interestGroupNames":- Set
result
'sinterestGroupNames
tokey value
.
- Set
- Otherwise, if
output["tags"]
equals to "keys":- Set
result
'skeys
tokey value
.
- Set
- Otherwise, if
output["tags"]
equals to "renderURLs":- Set
result
'srenderURLs
tokey value
.
- Set
- Otherwise, if
output["tags"]
equals to "adComponentRenderURLs":- Set
result
'sadComponentRenderURLs
tokey value
.
- Set
- If
- If
partition["dataVersion"]
exists, Setresult
'sdataVersion
topartition["dataVersion"]
. - Set
result
index
to tuple ofgroup["compressionGroupId"]
andpartition["id"]
. - Append
result
toresults
.
- If
- If
- Return
results
.
The Key Values Service is run by adtechs as service operators and relies on [HPKE] to encrypt communication between the client and the Key Value Service endpoint. This protects the confidentiality and integrity of requests and responses, particularly between the point of HTTPS/TLS termination and the TEE. By encrypting messages at this stage, [HPKE] prevents service operators from reading or modifying them in transit. While HPKE encryption protects message contents, the size of encrypted messages is still observable. This could potentially be exploited as a side-channel to leak information. Implementations MAY employ padding techniques described in this document to mitigate this risk.
To achieve specific privacy goals, clients can break up the request into separate partitions. Partitions prevent one interest group from influencing the response to another one. This isolation ensures that information remains compartmentalized and prevents unintended interference between interest groups.
A cross-site tracking risk exists where an adtech could attempt to link a user’s identity across different websites. An interest group owner could join a user to interest groups on multiple sites and observe changes in the request’s overall compression ratio. This protocol mitigates this risk by compressing interest groups for different sites separately.
An implementation should ensure that public keys used for encryption are obtained from a trusted source to prevent impersonation and unauthorized access. Private keys should be stored securely to prevent compromise.
For privacy considerations, see Key Value Service Trust Model.
TODO
--- back
An example of the [CBOR] representation for {{request-schema}} using the extended diagnostic notation from [CDDL] Appendix G:
{
"acceptCompression": [
"none",
"gzip"
],
"metadata": {
"hostname": "example.com"
},
"partitions": [
{
"id": 0,
"compressionGroupId": 0,
"metadata": {
"experimentGroupId": "12345",
"slotSize": "100,200",
},
"arguments": [
{
"tags": [
"interestGroupNames"
],
"data": [
"InterestGroup1"
]
},
{
"tags": [
"keys"
],
"data": [
"keyAfromInterestGroup1",
"keyBfromInterestGroup1"
]
}
]
},
{
"id": 1,
"compressionGroupId": 0,
"arguments": [
{
"tags": [
"interestGroupNames"
],
"data": [
"InterestGroup2",
"InterestGroup3"
]
},
{
"tags": [
"keys"
],
"data": [
"keyMfromInterestGroup2",
"keyNfromInterestGroup3"
]
}
]
}
]
}
An example of the [CBOR] representation for {{compression-group}} using the extended diagnostic notation from [CDDL] Appendix G:
[
{
"id": 0,
"keyGroupOutputs": [
{
"tags": [
"interestGroupNames"
],
"keyValues": {
"InterestGroup1": {
"value": "{\"priorityVector\":{\"signal1\":1}}"
}
}
},
{
"tags": [
"keys"
],
"keyValues": {
"keyAfromInterestGroup1": {
"value": "valueForA"
},
"keyBfromInterestGroup1": {
"value":"[\"value1ForB\",\"value2ForB\"]"
}
}
}
]
}
]
An example of {{interest-group-response}}.
{
"priorityVector": {
"aSignal": 1,
"anotherSignal": 2
},
"updateIfOlderThanMs": 10000
}
{:numbered="false"}
TODO