From c7ae28b91adf235c4957f0e092b5886ee26cf231 Mon Sep 17 00:00:00 2001 From: "Benjamin M. Case" <35273659+bmcase@users.noreply.github.com> Date: Mon, 5 Jan 2026 09:59:25 -0500 Subject: [PATCH 1/4] anti-replay requirements for level 1 anti-replay requirements -- just the basic ones from https://github.com/w3c/attribution/issues/43 not including partitioning and requerying. I have a separate branch with addition of associated data in the AEAD to partition reports but requires more changes and probably can wait till level 2 as @csharrison mentioned on the issue. --- api.bs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/api.bs b/api.bs index a5622b9..96ea413 100644 --- a/api.bs +++ b/api.bs @@ -2555,6 +2555,20 @@ that was expended by the site that requested the report. An [=aggregation service=] MUST guarantee that it does not accept the same report more than once. +To support anti-replay verification, +each [=conversion report=] includes associated data +that is authenticated as part of the AEAD encryption. +This associated data includes: + +* The [=origin=] of the caller invoking the {{Attribution/measureConversion()}} API. +* A timestamp, as determined by the device at the time of the API call. + +The [=aggregation service=] uses this associated data +to shard its anti-replay mechanism. +This sharding enables efficient verification +that each report is processed only once, +while allowing the service to scale. + # Differential Privacy # {#dp} From aa8bf3af9dc9bf841853281501f6f9baf78d1673 Mon Sep 17 00:00:00 2001 From: "Benjamin M. Case" <35273659+bmcase@users.noreply.github.com> Date: Mon, 5 Jan 2026 10:24:54 -0500 Subject: [PATCH 2/4] add topLevelSite in reportMetadata --- api.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.bs b/api.bs index 96ea413..c1450dd 100644 --- a/api.bs +++ b/api.bs @@ -2498,7 +2498,7 @@ and a [=list=] of [=integers=] |histogram|: mapped to the [=isomorphic encode|encoded=] value of |topLevelSite|[1]. 1. Let |reportMetadata| be encoded DAP [`ReportMetadata`](https://datatracker.ietf.org/doc/html/draft-ietf-ppm-dap-15#section-4.5.2) - generated from |reportID|, |time|, and |extensions|. + generated from |reportID|, |topLevelSite|, |time|, and |extensions|. 1. Let |encryptedInputShares| be an [=list/is empty|empty=] [=list=]. From 8261113485fe062f6162902a07d4575489af2514 Mon Sep 17 00:00:00 2001 From: "Benjamin M. Case" <35273659+bmcase@users.noreply.github.com> Date: Mon, 5 Jan 2026 10:55:12 -0500 Subject: [PATCH 3/4] use `site` consistently for anti-replay also makes it consistent with the privacy unit section https://w3c.github.io/attribution/#dp-unit --- api.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.bs b/api.bs index c1450dd..cc48ad4 100644 --- a/api.bs +++ b/api.bs @@ -2560,7 +2560,7 @@ each [=conversion report=] includes associated data that is authenticated as part of the AEAD encryption. This associated data includes: -* The [=origin=] of the caller invoking the {{Attribution/measureConversion()}} API. +* The [=site=] of the caller invoking the {{Attribution/measureConversion()}} API. * A timestamp, as determined by the device at the time of the API call. The [=aggregation service=] uses this associated data From 3ade7feeee5783816baeb17166d48847b72bed68 Mon Sep 17 00:00:00 2001 From: "Benjamin M. Case" <35273659+bmcase@users.noreply.github.com> Date: Mon, 5 Jan 2026 11:49:19 -0500 Subject: [PATCH 4/4] use `conversionCaller` in anti-replay --- api.bs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/api.bs b/api.bs index cc48ad4..1f0dd51 100644 --- a/api.bs +++ b/api.bs @@ -1560,6 +1560,7 @@ and [=implicit API inputs=] |implicitInputs|: 1. Let |encryptedReport| be the result of invoking construct a DAP report, given |validatedOptions|, |implicitInputs|' [=implicit API inputs/top-level site=], + |implicitInputs|' [=implicit API inputs/intermediary site=], |implicitInputs|' [=implicit API inputs/timestamp=], and |report|. 1. Let |result| be a {{AttributionConversionResult}} with the following items: @@ -2435,6 +2436,7 @@ To construct a DAP report, producing a [=byte sequence=] |report|, given [=validated conversion options=] |options|, [=site=] |topLevelSite|, +[=site=] or `undefined` |intermediarySite|, [=moment=] |now|, and a [=list=] of [=integers=] |histogram|: @@ -2497,8 +2499,11 @@ and a [=list=] of [=integers=] |histogram|: * The extension codepoint for [[DAP-EXT#name-requester-website-identity|requester identity]], mapped to the [=isomorphic encode|encoded=] value of |topLevelSite|[1]. +1. Let |conversionCaller| be |intermediarySite| if |intermediarySite| is not `undefined`, + |topLevelSite| otherwise. + 1. Let |reportMetadata| be encoded DAP [`ReportMetadata`](https://datatracker.ietf.org/doc/html/draft-ietf-ppm-dap-15#section-4.5.2) - generated from |reportID|, |topLevelSite|, |time|, and |extensions|. + generated from |reportID|, |conversionCaller|, |time|, and |extensions|. 1. Let |encryptedInputShares| be an [=list/is empty|empty=] [=list=]. @@ -2560,7 +2565,9 @@ each [=conversion report=] includes associated data that is authenticated as part of the AEAD encryption. This associated data includes: -* The [=site=] of the caller invoking the {{Attribution/measureConversion()}} API. +* The [=site=] that invoked the {{Attribution/measureConversion()}} API. + This is the [=intermediary site=] if the API was called from a cross-site frame, + or the [=conversion site=] otherwise. * A timestamp, as determined by the device at the time of the API call. The [=aggregation service=] uses this associated data