Skip to content

Commit a857522

Browse files
authored
Spec: filtering IDs (#123)
Specs the ability to set a filtering ID (and modify the default ID space). See https://github.com/patcg-individual-drafts/private-aggregation-api/blob/main/flexible_filtering.md#proposal-filtering-id-in-the-encrypted-payload and issue #92. To support this new functionality, we increase the report version. Note that this also requires aggregation service versions to support the new version.
1 parent e03bedb commit a857522

File tree

1 file changed

+90
-16
lines changed

1 file changed

+90
-16
lines changed

spec.bs

+90-16
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ interface PrivateAggregation {
131131
dictionary PAHistogramContribution {
132132
required bigint bucket;
133133
required long value;
134+
bigint filteringId = 0;
134135
};
135136

136137
dictionary PADebugModeOptions {
@@ -168,12 +169,22 @@ are:
168169
1. If |contribution|["{{PAHistogramContribution/value}}"] is negative,
169170
[=exception/throw=] a {{RangeError}}.
170171
1. Let |scopingDetails| be [=this=]'s [=PrivateAggregation/scoping details=].
172+
1. Let |batchingScope| be the result of running |scopingDetails|' [=scoping
173+
details/get batching scope steps=].
174+
1. Let |filteringIdMaxBytes| be the [=default filtering ID max bytes=].
175+
1. If [=pre-specified report parameters map=][|batchingScope|] [=map/exists=]:
176+
1. Set |filteringIdMaxBytes| to [=pre-specified report parameters
177+
map=][|batchingScope|]'s [=pre-specified report parameters/filtering ID
178+
max bytes=].
179+
1. If |contribution|["{{PAHistogramContribution/filteringId}}"] is not [=set/
180+
contained=] in [=the exclusive range|the range=] 0 to
181+
256<sup>|filteringIdMaxBytes|</sup>, exclusive, [=exception/throw=] a
182+
{{RangeError}}.
171183
1. Let |entry| be a new [=contribution cache entry=] with the items:
172184
: [=contribution cache entry/contribution=]
173185
:: |contribution|
174186
: [=contribution cache entry/batching scope=]
175-
:: The result of running |scopingDetails|' [=scoping details/get batching
176-
scope steps=].
187+
:: |batchingScope|
177188
: [=contribution cache entry/debug scope=]
178189
:: The result of running |scopingDetails|' [=scoping details/get debug scope
179190
steps=].
@@ -349,6 +360,8 @@ An aggregatable report is a [=struct=] with the following items:
349360
:: An [=aggregation coordinator=]
350361
: <dfn>context ID</dfn>
351362
:: A [=string=] or null
363+
: <dfn>filtering ID max bytes</dfn>
364+
:: A positive integer
352365
: <dfn>queued</dfn>
353366
:: A [=boolean=]
354367

@@ -379,6 +392,8 @@ items:
379392
<dl dfn-for="pre-specified report parameters">
380393
: <dfn>context ID</dfn> (default: null)
381394
:: A [=string=] or null
395+
: <dfn>filtering ID max bytes</dfn> (default: [=default filtering ID max bytes=])
396+
:: A positive integer
382397

383398
</dl>
384399

@@ -413,6 +428,18 @@ The user agent may expose controls that allow the user to delete data from the
413428
[=contribution cache=], the [=debug scope map=] and the [=pre-specified report
414429
parameters map=].
415430

431+
Constants {#constants}
432+
======================
433+
434+
<dfn>Default filtering ID max bytes</dfn> is a positive integer controlling the
435+
max bytes used if none is explicitly chosen. Its value is 1.
436+
437+
<dfn>Valid filtering ID max bytes range</dfn> is a [=set=] of positive integers
438+
controlling the allowable values of max bytes. Its value is [=the inclusive
439+
range|the range=] 1 to 8, inclusive.
440+
441+
Issue: Consider adding more constants.
442+
416443
[=Implementation-defined=] values {#implementation-defined-values}
417444
==================================================================
418445

@@ -510,12 +537,14 @@ To <dfn>determine if a report should be sent deterministically</dfn> given a
510537
steps. They return a [=boolean=]:
511538
1. If |preSpecifiedParams|' [=pre-specified report parameters/context ID=] is
512539
not null, return true.
540+
1. If |preSpecifiedParams|' [=pre-specified report parameters/filtering ID max
541+
bytes=] is not the [=default filtering ID max bytes=], return true.
513542
1. Return false.
514543

515-
Note: If a context ID was specified, a report is sent, even if there are no
516-
contributions or there is insufficent budget for the requested
517-
contributions. See [Protecting against leaks via the number of
518-
reports](#protecting-against-leaks-via-the-number-of-reports).
544+
Note: If a context ID or non-default filtering ID max bytes was specified, a
545+
report is sent, even if there are no contributions or there is insufficent
546+
budget for the requested contributions. See [Protecting against leaks via
547+
the number of reports](#protecting-against-leaks-via-the-number-of-reports).
519548

520549
To <dfn algorithm export>process contributions for a batching scope</dfn> given
521550
a [=batching scope=] |batchingScope|, an [=origin=] |reportingOrigin|, a
@@ -598,6 +627,10 @@ scope</dfn> given a [=pre-specified report parameters=] |params| and a
598627
1. Let |contextId| be |params|' [=pre-specified report parameters/context ID=].
599628
1. [=Assert=]: |contextId| is null or |contextId|'s [=string/length=] is not
600629
larger than 64.
630+
1. Let |filteringIdMaxBytes| be |params|' [=pre-specified report parameters/
631+
filtering ID max bytes=].
632+
1. [=Assert=]: |filteringIdMaxBytes| is [=set/contained=] in the [=valid
633+
filtering ID max bytes range=]
601634
1. [=map/Set=] [=pre-specified report parameters map=][|batchingScope|] to
602635
|params|.
603636

@@ -681,6 +714,9 @@ perform the following steps. They return an [=aggregatable report=].
681714
:: |aggregationCoordinator|
682715
: [=aggregatable report/context ID=]
683716
:: |preSpecifiedParams|' [=pre-specified report parameters/context ID=]
717+
: [=aggregatable report/filtering ID max bytes=]
718+
:: |preSpecifiedParams|' [=pre-specified report parameters/filtering ID max
719+
bytes=]
684720
: [=aggregatable report/queued=]
685721
:: false
686722
1. Return |report|.
@@ -909,21 +945,32 @@ To <dfn>obtain the plaintext payload</dfn> given an [=aggregatable report=]
909945
:: 0
910946
: {{PAHistogramContribution/value}}
911947
:: 0
948+
: {{PAHistogramContribution/filteringId}}
949+
:: 0
912950
1. [=list/Append=] |nullContribution| to |contributions|.
913951

914952
Note: This padding protects against the number of contributions being leaked
915953
through the encrypted payload size, see discussion
916954
[below](#protecting-against-leaks-via-payload-size).
917955
1. [=list/iterate|For each=] |contribution| of |report|'s [=aggregatable report/
918956
contributions=]:
957+
1. Let |filteringIdMaxBytes| be |report|'s [=aggregatable report/filtering
958+
id max bytes=].
959+
1. [=Assert=]: |contribution|["{{PAHistogramContribution/filteringId}}"]
960+
is [=set/contained=] in [=the exclusive range|the range=] 0 to
961+
256<sup>|filteringIdMaxBytes|</sup>, exclusive.
919962
1. Let |contributionData| be an [=ordered map=] of the following key/value
920963
pairs:
921964
: "`bucket`"
922965
:: The result of [=encoding an integer for the payload=] given
923-
|contribution|["{{PAHistogramContribution/bucket}}"] and 128.
966+
|contribution|["{{PAHistogramContribution/bucket}}"] and 16.
924967
: "`value`"
925968
:: The result of [=encoding an integer for the payload=] given
926-
|contribution|["{{PAHistogramContribution/value}}"] and 32.
969+
|contribution|["{{PAHistogramContribution/value}}"] and 4.
970+
: "`id`"
971+
:: The result of [=encoding an integer for the payload=] given
972+
|contribution|[="{{PAHistogramContribution/filteringId}}"] and
973+
|filteringIdMaxBytes|.
927974
1. [=list/Append=] |contributionData| to |payloadData|.
928975
1. Let |payload| be an [=ordered map=] of the following key/value pairs:
929976
: "`data`"
@@ -953,9 +1000,9 @@ They return a [=byte sequence=] or an error.
9531000
with |hpkeContext| and |aad|.
9541001

9551002
To <dfn>encode an integer for the payload</dfn> given an integer |intToEncode|
956-
and an integer |bitLength|, return the representation of |intToEncode| as a
957-
big-endian [=byte sequence=] of length |bitLength| / 8, left padding with zeroes
958-
as necessary.
1003+
and an integer |byteLength|, return the representation of |intToEncode| as a
1004+
big-endian [=byte sequence=] of length |byteLength|, left padding with zeroes as
1005+
necessary.
9591006

9601007
To <dfn>obtain a report's shared info</dfn> given an [=aggregatable report=]
9611008
|report|, perform the following steps. They return a [=string=].
@@ -973,7 +1020,7 @@ To <dfn>obtain a report's shared info</dfn> given an [=aggregatable report=]
9731020
:: The number of seconds in |scheduledReportTime|, rounded down to the
9741021
nearest number of whole seconds and [=serialize an integer|serialized=]
9751022
: "`version`"
976-
:: "`0.1`"
1023+
:: "`1.0`"
9771024
1. Return the result of [=serializing an infra value to a json string=] given
9781025
|sharedInfo|.
9791026

@@ -1038,6 +1085,7 @@ partial interface SharedStorageWorkletGlobalScope {
10381085
dictionary SharedStoragePrivateAggregationConfig {
10391086
USVString aggregationCoordinatorOrigin;
10401087
USVString contextId;
1088+
[EnforceRange] unsigned long long filteringIdMaxBytes;
10411089
};
10421090

10431091
partial dictionary SharedStorageRunOperationMethodOptions {
@@ -1078,15 +1126,25 @@ steps. They return a [=pre-specified report parameters=], null, or a
10781126
{{DOMException}}:
10791127
1. If |options|["{{SharedStorageRunOperationMethodOptions/privateAggregationConfig}}"]
10801128
does not [=map/exist=], return null.
1129+
1. Let |privateAggregationConfig| be
1130+
|options|["{{SharedStorageRunOperationMethodOptions/privateAggregationConfig}}"].
10811131
1. Let |contextId| be null.
1082-
1. If |options|["{{SharedStorageRunOperationMethodOptions/privateAggregationConfig}}"]["{{SharedStoragePrivateAggregationConfig/contextId}}"]
1132+
1. If |privateAggregationConfig|["{{SharedStoragePrivateAggregationConfig/contextId}}"]
10831133
[=map/exists=], set |contextId| to
1084-
|options|["{{SharedStorageRunOperationMethodOptions/privateAggregationConfig}}"]["{{SharedStoragePrivateAggregationConfig/contextId}}"].
1134+
|privateAggregationConfig|["{{SharedStoragePrivateAggregationConfig/contextId}}"].
10851135
1. If |contextId|'s [=string/length=] is greater than 64, return a new
10861136
{{DOMException}} with name "`DataError`".
1137+
1. Let |filteringIdMaxBytes| be the [=default filtering ID max bytes=].
1138+
1. If |privateAggregationConfig|["{{SharedStoragePrivateAggregationConfig/filteringIdMaxBytes}}"]
1139+
[=map/exists=], set |filteringIdMaxBytes| to
1140+
|privateAggregationConfig|["{{SharedStoragePrivateAggregationConfig/filteringIdMaxBytes}}"].
1141+
1. If |filteringIdMaxBytes| is not [=set/contained=] in the [=valid filtering ID
1142+
max bytes range=], return a new {{DOMException}} with name "`DataError`".
10871143
1. Return a new [=pre-specified report parameters=] with the items:
10881144
: [=pre-specified report parameters/context ID=]
10891145
:: |contextId|
1146+
: [=pre-specified report parameters/filtering ID max bytes=]
1147+
:: |filteringIdMaxBytes|
10901148

10911149
The {{WindowSharedStorage}}'s {{WindowSharedStorage/run()}} method steps are
10921150
modified in four ways. First, add the following steps just after step 2 ("If
@@ -1282,6 +1340,7 @@ dictionary PASignalValue {
12821340
dictionary PAExtendedHistogramContribution {
12831341
required (PASignalValue or bigint) bucket;
12841342
required (PASignalValue or long) value;
1343+
bigint filteringId = 0;
12851344
};
12861345

12871346
[Exposed=InterestGroupScriptRunnerGlobalScope, SecureContext]
@@ -1349,9 +1408,16 @@ event, PAExtendedHistogramContribution contribution)</dfn> method steps are:
13491408
throw=] a {{TypeError}}.
13501409
1. Otherwise, if |contribution|["{{PAHistogramContribution/value}}"] is
13511410
negative, [=exception/throw=] a {{TypeError}}.
1411+
1. If |contribution|["{{PAExtendedHistogramContribution/filteringId}}"] is
1412+
not [=set/contained=] in [=the exclusive range|the range=] 0 to
1413+
256<sup>[=default filtering ID max bytes=]</sup>, exclusive, [=exception/
1414+
throw=] a {{TypeError}}.
13521415

13531416
Issue: Make the error types on validation issues here and above consistent
13541417
with {{PrivateAggregation/contributeToHistogram(contribution)}}.
1418+
1419+
Note: It is not currently possible to set a non-default filtering ID max
1420+
bytes for Protected Audience.
13551421
1. Let |batchingScope| be null.
13561422
1. If |event| [=string/starts with=] "`reserved.`", set |batchingScope| to the
13571423
result of running |scopingDetails|' [=scoping details/get batching scope
@@ -1974,7 +2040,10 @@ an <a spec="turtledove">auction config</a> |auctionConfig| and a
19742040
:: |bucket|
19752041
: {{PAHistogramContribution/value}}
19762042
:: |value|
2043+
: {{PAHistogramContribution/filteringId}}
2044+
:: 0
19772045

2046+
Issue: Consider allowing the filtering ID to be set here.
19782047
1. [=map/For each=] |ig| of the [=user agent=]'s <a spec="turtledove">
19792048
interest group set</a> whose
19802049
<a spec="turtledove" for="interest group">owner</a> is
@@ -2029,11 +2098,15 @@ following steps. They return a {{PAHistogramContribution}}.
20292098
1. Let |value| be |contribution|["{{PAExtendedHistogramContribution/value}}"].
20302099
1. If |value| is a {{PASignalValue}}, set |value| to the result of [=filling in
20312100
the signal value=] given |value|, 2<sup>31</sup>−1 and |leadingBidInfo|.
2032-
1. Return a new {{PAHistogramContribution}} with the items:
2101+
1. Let |filledInContribution| be a new {{PAHistogramContribution}} with the
2102+
items:
20332103
: {{PAHistogramContribution/bucket}}
20342104
:: |bucket|
20352105
: {{PAHistogramContribution/value}}
20362106
:: |value|
2107+
: {{PAHistogramContribution/filteringId}}
2108+
:: |contribution|["{{PAExtendedHistogramContribution/filteringId}}"]
2109+
1. Return |filledInContribution|.
20372110

20382111
To <dfn>fill in the signal value</dfn> given a {{PASignalValue}} |value|, an
20392112
integer |maxAllowed| and a <a spec="turtledove">leading bid info</a>
@@ -2218,7 +2291,8 @@ However, the number of reports with the given metadata could expose some
22182291
cross-site information. To protect against this, the API delays sending reports
22192292
by a randomized amount of time to make it difficult to determine whether a
22202293
report was sent or not from any particular event. In the case that a
2221-
[=aggregatable report/context ID=] is supplied, the API makes the number of
2294+
[=aggregatable report/context ID=] is supplied or a non-default [=aggregatable
2295+
report/filtering ID max bytes=] is specified, the API makes the number of
22222296
reports sent deterministic (sending 'null reports' if necessary -- each
22232297
containing only a contribution with a value of 0 in the payload). Additional
22242298
mitigations may also be possible in the future, e.g. adding noise to the report

0 commit comments

Comments
 (0)