[go: up one dir, main page]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specify and validate event_level_epsilon #1097

Merged
merged 5 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 10 additions & 5 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1182,9 +1182,10 @@ controls the maximum [=map/size=] of a [=trigger spec map=] for an
controls how many [=attribution sources=] can be in the
[=attribution source cache=] per [=attribution source/source origin=].

<dfn>Randomized response epsilon</dfn> is a non-negative double that controls
the randomized response probability of an [=attribution source=]. If [=automation local testing mode=] is true,
this is `∞`.
<dfn>Max settable event-level epsilon</dfn> is a non-negative double that
controls the default and maximum values that a source registration can specify
for the epsilon parameter used by [=compute the channel capacity of a source=]
and [=obtain a randomized source response=].

<dfn>Randomized null report rate excluding source registration time</dfn> is a
double between 0 and 1 (both inclusive) that controls the randomized number of null reports
Expand Down Expand Up @@ -1990,7 +1991,10 @@ To <dfn noexport>parse source-registration JSON</dfn> given a [=byte sequence=]
: [=randomized response output configuration/trigger specs=]
:: |triggerSpecs|

1. Let |epsilon| be the user agent's [=randomized response epsilon=].
1. Let |epsilon| be the user agent's [=max settable event-level epsilon=].
1. Set |epsilon| to |value|["`event_level_epsilon`"] if it [=map/exists=]:
1. If |epsilon| is not a double, is less than 0, or is greater than the user agent's [=max settable event-level epsilon=], return null.
1. If [=automation local testing mode=] is true, set |epsilon| to `∞`.
1. If the result of [=computing the channel capacity of a source=] with |randomizedResponseConfig| and |epsilon| is greater than
[=max event-level channel capacity per source=][|sourceType|], return null.
1. Let |triggerDataMatchingMode| be "<code>[=trigger-data matching mode/modulus=]</code>".
Expand Down Expand Up @@ -3916,7 +3920,8 @@ Any given [=attribution source=] has a [=obtain a set of possible trigger states
The choice of trigger state may encode cross-site information. To protect the cross-site information disclosure,
each [=attribution source=] is subject to a [=obtain a randomized response|randomized response mechanism=] [[RR]],
which will choose a state at random with [=obtain a randomized source response pick rate|pick rate=]
dependent on the user agent's [=randomized response epsilon=].
dependent on the source's event-level epsilon, which has an upper bound of the
user agent's [=max settable event-level epsilon=].

This introduces some level of plausible deniability into the resulting [=event-level reports=] (or lack thereof),
as there is always a chance that the output was generated from a random process. We can reason about the
Expand Down
6 changes: 3 additions & 3 deletions params/chromium-params.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Chromium's implementation assigns the following values:
| Name | Value |
| ---- | ----- |
| [Max pending sources per source origin][] | [4096][max pending sources per source origin value] |
| [Randomized response epsilon][] | [14][randomized response epsilon value] |
| [Max settable event-level epsilon][] | [14][max settable event-level epsilon value] |
| [Randomized null report rate excluding source registration time][] | [0.05][randomized null report rate excluding source registration time value] |
| [Randomized null report rate including source registration time][] | [0.008][randomized null report rate including source registration time value] |
| [Max event-level reports per attribution destination][] | [1024][max event-level reports per attribution destination value] |
Expand All @@ -28,8 +28,8 @@ Chromium's implementation assigns the following values:

[Max pending sources per source origin]: https://wicg.github.io/attribution-reporting-api/#max-pending-sources-per-source-origin
[max pending sources per source origin value]: https://source.chromium.org/chromium/chromium/src/+/main:content/browser/attribution_reporting/attribution_config.h;l=151;drc=3be0e68c5ed56aba7c321cbaea22558eee61fc50
[Randomized response epsilon]: https://wicg.github.io/attribution-reporting-api/#randomized-response-epsilon
[randomized response epsilon value]: https://source.chromium.org/chromium/chromium/src/+/main:content/browser/attribution_reporting/attribution_config.h;l=57;drc=3733a639d724a4353463a872605119d11a1e4d37
[Max settable event-level epsilon]: https://wicg.github.io/attribution-reporting-api/#max-settable-event-level-epsilon
[max settable event-level epsilon value]: https://source.chromium.org/chromium/chromium/src/+/main:content/browser/attribution_reporting/attribution_config.h;l=57;drc=3733a639d724a4353463a872605119d11a1e4d37
[Randomized null report rate excluding source registration time]: https://wicg.github.io/attribution-reporting-api/#randomized-null-report-rate-excluding-source-registration-time
[randomized null report rate excluding source registration time value]: https://source.chromium.org/chromium/chromium/src/+/main:content/browser/attribution_reporting/attribution_config.h;l=109;drc=3733a639d724a4353463a872605119d11a1e4d37
[Randomized null report rate including source registration time]: https://wicg.github.io/attribution-reporting-api/#randomized-null-report-rate-including-source-registration-time
Expand Down
52 changes: 50 additions & 2 deletions ts/src/header-validator/source.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const testCases: TestCase[] = [
debugKey: 1n,
debugReporting: true,
destination: new Set(['https://a.test']),
eventLevelEpsilon: 14,
eventReportWindows: {
startTime: 0,
endTimes: [3601],
Expand Down Expand Up @@ -1186,7 +1187,7 @@ const testCases: TestCase[] = [
[SourceType.event]: 0,
[SourceType.navigation]: Infinity,
},
randomizedResponseEpsilon: 14,
maxSettableEventLevelEpsilon: 14,
},
expectedErrors: [
{
Expand All @@ -1204,7 +1205,7 @@ const testCases: TestCase[] = [
[SourceType.event]: Infinity,
[SourceType.navigation]: 0,
},
randomizedResponseEpsilon: 14,
maxSettableEventLevelEpsilon: 14,
},
expectedErrors: [
{
Expand All @@ -1214,6 +1215,53 @@ const testCases: TestCase[] = [
],
},

{
name: 'event-level-epsilon-valid',
json: `{
"destination": "https://a.test",
"event_level_epsilon": 13.5
}`,
},
{
name: 'event-level-epsilon-wrong-type',
json: `{
"destination": "https://a.test",
"event_level_epsilon": "1"
}`,
expectedErrors: [
{
path: ['event_level_epsilon'],
msg: 'must be a number',
},
],
},
{
name: 'event-level-epsilon-negative',
json: `{
"destination": "https://a.test",
"event_level_epsilon": -1
}`,
expectedErrors: [
{
path: ['event_level_epsilon'],
msg: 'must be in the range [0, 14]',
},
],
},
{
name: 'event-level-epsilon-above-max',
json: `{
"destination": "https://a.test",
"event_level_epsilon": 14.1
}`,
expectedErrors: [
{
path: ['event_level_epsilon'],
msg: 'must be in the range [0, 14]',
},
],
},

// Full Flex
// TODO: compare returned trigger specs against expected values

Expand Down
15 changes: 14 additions & 1 deletion ts/src/header-validator/validate-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,12 @@ function eventReportWindow(
)
}

function eventLevelEpsilon(ctx: Context, j: Json): Maybe<number> {
return number(ctx, j).filter((n) =>
isInRange(ctx, n, 0, ctx.vsv.maxSettableEventLevelEpsilon)
)
}

function channelCapacity(ctx: Context, s: Source): void {
const perTriggerDataConfigs = s.triggerSpecs.flatMap((spec) =>
Array(spec.triggerData.size).fill(
Expand All @@ -808,7 +814,7 @@ function channelCapacity(ctx: Context, s: Source): void {
)

const { infoGain } = config.computeConfigData(
ctx.vsv.randomizedResponseEpsilon,
s.eventLevelEpsilon,
ctx.vsv.maxEventLevelChannelCapacityPerSource[ctx.sourceType]
)

Expand Down Expand Up @@ -1039,6 +1045,8 @@ export type Source = CommonDebug &

triggerSpecs: TriggerSpec[]
triggerDataMatching: TriggerDataMatching

eventLevelEpsilon: number
}

function source(ctx: Context, j: Json): Maybe<Source> {
Expand Down Expand Up @@ -1092,6 +1100,11 @@ function source(ctx: Context, j: Json): Maybe<Source> {
),
aggregationKeys: field('aggregation_keys', aggregationKeys, new Map()),
destination: field('destination', destination),
eventLevelEpsilon: field(
'event_level_epsilon',
eventLevelEpsilon,
ctx.vsv.maxSettableEventLevelEpsilon
),
eventReportWindows: () => eventReportWindowsVal,
expiry: () => expiryVal,
filterData: field('filter_data', filterData, new Map()),
Expand Down
4 changes: 2 additions & 2 deletions ts/src/vendor-specific-values.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { SourceType } from './source-type'

export type VendorSpecificValues = {
maxEventLevelChannelCapacityPerSource: Record<SourceType, number>
randomizedResponseEpsilon: number
maxSettableEventLevelEpsilon: number
}

export const Chromium: Readonly<VendorSpecificValues> = {
maxEventLevelChannelCapacityPerSource: {
[SourceType.event]: 6.5,
[SourceType.navigation]: 11.46173,
},
randomizedResponseEpsilon: 14,
maxSettableEventLevelEpsilon: 14,
}