Internet-Draft | KV Services | January 2025 |
Hu, et al. | Expires 17 July 2025 | [Page] |
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.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 17 July 2025.¶
Copyright (c) 2025 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
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 (Section 2.3) and consumes Responses (Section 2.4). 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:¶
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 (Section 2.2.3). 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 Section 2.3.3) 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 Section 2.4.3.1) 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 Section 2.4.3.1). 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 Section 2.2.1.¶
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 the
Key Identifier
, HPKE KEM ID
, HPKE KDF ID
, and HPKE 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, and hdr
.¶
Create a sending HPKE context by invoking SetupBaseS()
(Section 5.1.1 of [HPKE])
with the public key of the receiver pkR
and info
. This yields the context
sctxt
and an encapsulation key enc
.¶
Encrypt request
by invoking the Seal()
method on sctxt
(Section 5.2 of [HPKE])
with empty associated data aad
, yielding ciphertext ct
.¶
Concatenate the values of hdr
, enc
, and ct
.¶
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 Section 2.4.1).¶
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
into key_id
, kem_id
, kdf_id
, aead_id
,
enc
, and ct
.¶
Find the matching HPKE private key, skR
, corresponding to key_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; plus
kem_id
, kdf_id
, and aead_id
as three 16-bit integers.¶
Create a receiving HPKE context, rctxt
, by invoking SetupBaseR()
(Section 5.1.1 of [HPKE])
with skR
, enc
, and info
.¶
Decrypt ct
by invoking the Open()
method on rctxt
(Section 5.2 of [HPKE]),
with an empty associated data aad
, yielding request
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 Section 2.2.2.¶
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. }¶
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 with public key
.
* a metadata
map for global configuration, where both keys and
values are strings.
* a compression groups
, which is a list of group
s, each
with the following parameters:
* a compressionGroupId
integer identifier of this compression
group.
* a partitions
, which is a list of partition
s belonging to this compression
group. Each partition
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.¶
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
in compression groups
:¶
For each partition
in group
's partitions
:
1. Let p
be an empty map.
1. Set p["compressionGroupId"]
to group
's compressionGroupId
.
1. Set p["id"]
to partition
's id
.
1. Set p["metadata"]
to partition
's metadata
.
1. Let arguments
be an empty array.
1. For each tag
→ value
in partition
's namespace
:¶
Set request map["metadata"]
to metadata
.¶
Set request map["partitions"]
to partitions
.¶
Set request map["acceptCompression"]
to ["none", "gzip"]
.¶
Create a framed payload
, as described in Section 2.2.2:¶
Create a Section 2.2.2 header framing header
.¶
Set framing header
's Compression
to 1.¶
Set framing header
's Size
to the size of payload
.¶
Set framed payload
to the concatenation of framing header
and payload
.¶
Padding MAY be added to framed payload
.¶
Return an empty request
on failure of any of the previous steps.¶
[HPKE] encrypt framed payload
using public key
and key id
as in Section 2.3.1 to get the [HPKE] encrypted ciphertext request
and [HPKE] encryption context request context
.¶
Return request
and request 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 to
key_id
as described in Section 2.3.1, to get the decrypted message and rctxt
.¶
Remove and extract the first 5 bytes from framed request
as the framing header
(described in
Section 2.2.2), removing them from framed request
.¶
If the framing header
's Compression
field is not 0x00
(no compression), return failure.¶
Let length
be equal to the framing header
's Size
field.¶
If length
is greater than the length of the remaining bytes in framed request
, return
failure.¶
Take the first length
remaining bytes in framed response
as decodable request
, discarding
the rest.¶
[CBOR] decode decodable request
into the message represented in Section 2.3.3. Let this be
processed request
.¶
If decoding fails, return failure.¶
If no partitions
are present, return failure.¶
Set compressionGroupMap
to an empty map.¶
For each partition
in partitions
:¶
Return processed request
, compressionGroupMap
, and rctxt
.¶
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
) from context
, using the string
"message/ad-auction-trusted-signals-response" as the exporter_context
parameter to
context.Export
; see Section 5.3
of [HPKE]. The length of this secret is max(Nn, Nk)
, where Nn
and Nk
are
the length of the AEAD key and nonce that are associated with context
.¶
Generate a random value of length max(Nn, Nk)
bytes, called response_nonce
.¶
Extract a pseudorandom key (prk
) using the Extract
function provided by
the KDF algorithm associated with context. The ikm
input to this function
is secret
; the salt
input is the concatenation of enc
(from
enc_request
) and response_nonce
.¶
Use the Expand
function provided by the same KDF to create an AEAD key,
key
, of length Nk
-- the length of the keys used by the AEAD associated
with context
. Generating aead_key
uses a label of "key".¶
Use the same Expand
function to create a nonce, nonce
, of length Nn
-- the length of the nonce used by the AEAD. Generating aead_nonce
uses a
label of "nonce".¶
Encrypt response
, passing the AEAD function Seal
the values of aead_key
,
aead_nonce
, an empty aad
, and a pt
input of response
. This yields ct
.¶
Concatenate response_nonce
and ct
, yielding an Encapsulated Response,
enc_response
. Note that response_nonce
is of fixed length, so there is no
ambiguity in parsing either response_nonce
or ct
.¶
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 Section 2.2.2.¶
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 Section 2.4.3 as well as
the compressionGroupMap
and the HPKE receiver, rctxt
, context saved in Section 2.3.5.
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 Section 2.4.3.¶
Set compression groups
to an empty list.¶
Set partitionOutputMap
to an empty map.¶
For each partitionOutput
in the list of partitionOutputs
:¶
Set partitionOutputMap[partitionOutput["id"]]
to partitionOutput
.¶
For each (compression group id
, partition ids
) in compressionGroupMap
:¶
Create an empty compression group
object, corresponding to Section 2.4.3.1.¶
Set cbor partitions array
to an empty CBOR array.¶
For each partition id
in partition ids
:¶
Set cbor serialized payload
to the CBOR serialized cbor partitions array
.¶
On serialization failure, continue.¶
Set compression group content
to the [GZIP] compressed cbor serialized payload
.¶
On failure, continue.¶
Set compression group["compressionGroupId"]
to compression group id
¶
Set compression group["content"]
to compression group content
.¶
Add compression group
to compression groups
.¶
Set payload["compressionGroups"]
to compression groups
.¶
Create a framed payload, as described in Section 2.2.2:¶
Create a framing header
.¶
Set the framing header
Compression
to one of 2.¶
Set the framing header
Size
to the size of compressed payload
.¶
Let framed payload
equal the result of prepending the framing header to
payload
.¶
Padding MAY be added to framed payload
.¶
Return an empty response
on failure of any of the previous steps.¶
Let response
equal the result of the encryption and encapsulation of framed payload
with
rctxt
, as described in Section 2.4.1. Return an empty response
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
Section 2.3.4, and an encrypted response
, an array of bytes
from the Key Value Service generated by Section 2.4.5.¶
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 decrypt encrypted response
and obtain framed response
, returning failure if decryption fails.¶
Remove and extract the first 5 bytes from framed response
as the framing header (described in Section 2.2.2), removing them from framed response
.¶
If framing header
's Compression
field is not 0 or 2, return failure.¶
Let length
be equal to the framing header
's Size
field.¶
If length
is greater than the length of the remaining bytes in framed response
, return failure.¶
Take the first length
remaining bytes in framed response
as serialized response
, discarding the rest.¶
[CBOR] decode the serialized response
into response
, 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
in response["compressionGroups"]
:¶
If group
is not a map, return failure.¶
If group["content"]
does not exist, return failure.¶
Set serialized content
to the result of decompressing group["content"]
according to the compression algorithm specified in the framing header
's Compression
field, returning failure if decompression fails.¶
[CBOR] decode the serialized content
into content
, returning failure if decoding fails.¶
If content
is not an array, return failure.¶
For each partition
in content
:¶
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
in partition["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
in output["keyValues"]
:¶
If output["tags"]
equals to "interestGroupNames":¶
Set result
's interestGroupNames
to key value
.¶
Otherwise, if output["tags"]
equals to "keys":¶
Set result
's keys
to key value
.¶
Otherwise, if output["tags"]
equals to "renderURLs":¶
Set result
's renderURLs
to key value
.¶
Otherwise, if output["tags"]
equals to "adComponentRenderURLs":¶
Set result
's adComponentRenderURLs
to key value
.¶
If partition["dataVersion"]
exists, Set result
's dataVersion
to partition["dataVersion"]
.¶
Set result
index
to tuple of group["compressionGroupId"]
and partition["id"]
.¶
Append result
to results
.¶
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¶
An example of the [CBOR] representation for Section 2.3.3 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 Section 2.4.3.1 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 Section 2.4.4.1.¶
{ "priorityVector": { "aSignal": 1, "anotherSignal": 2 }, "updateIfOlderThanMs": 10000 }¶
TODO¶