[go: up one dir, main page]

Skip to content

Commit

Permalink
Specify and validate event_level_epsilon (#1097)
Browse files Browse the repository at this point in the history
Co-authored-by: Charlie Harrison <csharrison@chromium.org>
  • Loading branch information
apasel422 and csharrison committed Nov 29, 2023
1 parent d4b1f0b commit 722af9e
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 13 deletions.
15 changes: 10 additions & 5 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1178,9 +1178,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 @@ -1986,7 +1987,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 @@ -3904,7 +3908,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 @@ -1057,6 +1063,8 @@ export type Source = CommonDebug &

triggerSpecs: TriggerSpec[]
triggerDataMatching: TriggerDataMatching

eventLevelEpsilon: number
}

function source(ctx: Context, j: Json): Maybe<Source> {
Expand Down Expand Up @@ -1110,6 +1118,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,
}

0 comments on commit 722af9e

Please sign in to comment.