Original text:
"time_precision" in order to ensure that that the timestamp cannot be used to link a report back to the Client that generated it. <del> A list of extensions to be included with the report.  (See upload- extensions.) </del>  <del> To generate a report, the Client first shards its measurement into input shares as specified by the VDAF.  It then encrypts each input share as follows: </del>  where "pk" is the aggregator's public key; "server_role" is the Role of the intended recipient ("0x02" for the leader and "0x03" for the <del> helper), "input_share" is the Aggregator's input share, and "input_share_aad" is an encoded message of type "InputShareAad", constructed from the same values as the corresponding fields in the report.  The "SealBase()" function is as specified in HPKE for the ciphersuite indicated by the HPKE configuration. </del>  The order of the encrypted input shares appear MUST match the order of the task's "aggregator_endpoints".  That is, the first share rejects a report for this reason, it SHOULD abort the upload protocol and alert the client with error "reportTooEarly".  4.3.3. <del> Each Report carries a list of extensions that clients may use to convey additional, authenticated information in the report.  [OPEN ISSUE: The extensions aren't authenticated.  It's probably a good idea to be a bit more clear about how we envision extensions being used.  Right now this includes client attestation for defeating Sybil attacks.  See issue#89.]  Each extension is a tag-length encoded value of the following form: </del>  <del> "extension_type" indicates the type of extension, and </del>  "extension_data" contains information specific to the extension.  4.3.4. The contents of each input share must be kept confidential from 4.4.1.3. Each report share has a corresponding task ID, report metadata <del> (report ID, timestamp, and extensions), the public share sent to each Aggregator, and the recipient's encrypted input share.  Let "task_id", "metadata", "public_share", and "encrypted_input_share" denote these values, respectively.  Given these values, an aggregator decrypts the input share as follows.  First, the aggregator looks up the HPKE config and corresponding secret key indicated by </del>  "encrypted_input_share.config_id".  If not found, then it marks the report share as invalid with the error "hpke_unknown_config_id". Otherwise, it constructs an "InputShareAad" message from "task_id", the aggregator ("0x02" for the leader and "0x03" for the helper).  If decryption fails, the aggregator marks the report share as invalid with the error "hpke_decrypt_error".  Otherwise, it outputs the <del> resulting "input_share".  The "OpenBase()" function is as specified in HPKE for the ciphersuite indicated by the HPKE configuration. </del>  4.4.1.4. "task_expiration" time, if so the Aggregator MAY mark the input share as invalid with the error "task_expired".  Finally, if an Aggregator cannot determine if an input share is valid. it MUST mark the input share as invalid with error "report_dropped".  This situation arises if, for example, the "0x01" for the helper); "agg_param" is the opaque aggregation parameter distributed to the aggregators by the collector; "public_share" is the public share generated by the client and <del> distributed to each aggregator; and "input_share" is the aggregator's input share. </del>  If either step fails, the aggregator marks the report as invalid with error "vdaf_prep_error".  Otherwise, the value "out" is interpreted

Reviewer comments:
Rebased and squashed.
Rebased and squashed.
NAME I've removed the shared extensions as discussed. Can you take another look and re-approve?
As noted by NAME in URL, we need to decide how to handle duplicate extensions. One simple idea is to treat duplicate extensions as decoding failures, i.e., abort with "unrecognizedMessage".
Are unknown/unsupported extensions ignored?
First off, just for clarity's sake, I'm assuming Martin is talking about . I think there are three ways to solve this problem. First, unknown extensions could be ignored by the aggregators. I believe this is the intent of the existing text (though I acknowledge that the protocol text would need to be updated to make that clear). I think this would work for the two report extension use cases I'm aware of at the moment, which are client authentication to the helper and . In either case, the aggregator can ignore the extension, proceed with the protocol and I don't think anything disastrous happens. If the aggregator doesn't support client auth extensions, it simply proceeds with processing the report upload after applying whatever other security policy it wants to the report. If the aggregator doesn't support the taskprov extension, then the upload will fail gracefully and reliably because the aggregator doesn't recognize the task ID referenced by the report. This is simple and flexible, but it does mean that all extensions ever deployed in DAP need to be designed such that they can be gracefully ignored by aggregators. The second way to handle this would be to use something like (ugh) X.509's extension criticality bit, which would appear alongside an extension and if set to true, would indicate to servers that they should abort processing of an upload with some error like , the idea being that further handling of the report without handling the extension is too dangerous. However, anytime I'm reaching out to (ugh) X.509 for ideas, I take that as a sign that maybe we're solving the wrong problem or doing something too complicated. But I think the reason X.509 ends up needing a criticality bit is because at the time of issuance of a certificate, it's not known (and not knowable) what is the set of implementations of relying parties, servers, CT logs, audit tools, etc. that might ever see the cert, and so special care must be taken to account for the diversity of implementations. But in DAP, when a client is putting extensions into its reports, it's doing so with knowledge of the specific pair of aggregators to which it is uploading the report, so I think it's more reasonable to expect the client to know precisely what extensions the aggregators support. We have discussed having servers advertise what HPKE algorithms they support in , so advertising supported extensions is a minor step beyond that. So the third option is to treat all extensions as critical, and require servers to abort if they don't recognize them. This is the least flexible, but I also think it's the easiest one to reason about, both for the DAP protocol and eventual extension authors. All that said, I think I'll tentatively vote for all extensions implicitly being critical, but I'm open to having my mind changed.
I would prefer to make extensions ignored by default, as they are in TLS. That puts it to extension designers to make sure their extensions can be safely ignored. If an extension can't be safely ignored, we should consider merging it into the core protocol. See URL for additional discussion.
To be clear NAME the spec is not clear here yet, hence :)
I apologize for splitting the discussion. I tend to side with NAME conclusions. If nothing else, the aggregators can publish what they accept ahead of time, along with keys.
I think my only concern with the third option is this: Suppose that, in some DAP deployment, the Client and Leader used some extension that is irrelevant to the Helper. For instance, imagine the Client produces some attestation () that the report was generated on a Leader-trusted device. The Helper may not be able to do this check. I guess you could argue that both Aggregators should be doing this check, in which case option 3 is actually what we want? This would probably depend on the threat model for the extension.
So are these extensions universal in the sense that the same extension applies to the data that is sent to all helpers (including the leader) or, as I believe is the case, the extensions are targeted and they are sent separately to each of the helpers? In the latter case, the client can condition what it sends on what it knows about the specific helper that it is sending to. Yes, that makes it more complicated for a client, but that is the nature of the trade-off.
The latter is what I'm imagining, yes. Hmm that's a pretty good idea, though (1) it would require some protocol changes (currently the Leader "re-transmits" all of the extensions to each Helper) and (2) we would have to unbind the extensions from the HPKE ciphertext (currently the extensions are included in the AAD for encryption). (1) seems workable to me; (2) doesn't seem desirable from a security perspective. (Fiddling with extensions should result in the report being excluded, hence the current binding.)
Thinking about it more, we don't have to do (2). Perhaps all we have to do is mark each extension with the identity of the intended consumer? Some extensions might be intended for the Leader, others for the Helper, others for both.
Why not move the extensions to the encrypted payload? Sure, the client replicates extensions toward each helper, but you avoid a lot of this complexity.
That could work, but I think we should avoid copying extensions. (People are worried about communication cost of DAP.)
I'd be down for something like this: Treat Report.extensions as "critical", in the sense that any unrecognized extension triggers an abort. Add an extensions field to the plaintext for each Report.encryptedinputshare.payload (HPKE ciphertext). Alternatively, we could add a new field to Report.encryptedinputshare. Either way, the consumer treats these as critical. NAME WDYT?
The idea being to (1) enable a client to send different extensions to either aggregator and (2) keep the extensions intended for the helper private from the leader? Yeah, seems like a good idea!
It would be great to work this out in DAP-03. I'll try to put together a PR for NAME suggestion next week, if no one else gets there first.
PR is up, please have a look!
Noticed a typo, otherwise LGTM.

Revised text:
"time_precision" in order to ensure that that the timestamp cannot be used to link a report back to the Client that generated it.  <ins> To generate a report, the Client begins by sharding its measurement into input shares as specified by the VDAF.  It then wraps each input share in the following structure: </ins>  <ins> Field "extensions" is set to the list of extensions intended to be consumed by the given Aggregator.  (See upload-extensions.)  Field "payload" is set to the Aggregator's input share output by the VDAF sharding algorithm. Next, the Client encrypts each PlaintextInputShare "plaintext_input_share" as follows: </ins> where "pk" is the aggregator's public key; "server_role" is the Role of the intended recipient ("0x02" for the leader and "0x03" for the  <ins> helper), "plaintext_input_share" is the Aggregator's PlaintextInputShare, and "input_share_aad" is an encoded message of type "InputShareAad", constructed from the same values as the corresponding fields in the report.  The "SealBase()" function is as specified in HPKE for the ciphersuite indicated by the HPKE configuration. </ins> The order of the encrypted input shares appear MUST match the order of the task's "aggregator_endpoints".  That is, the first share rejects a report for this reason, it SHOULD abort the upload protocol and alert the client with error "reportTooEarly". <ins> If the Report contains an unrecognized extension, then the Leader MAY abort the upload request with error "unrecognizedMessage".  Note that this behavior is not mandatory because it requires the Leader to decrypt its input share. </ins> 4.3.3.  <ins> Each PlaintextInputShare carries a list of extensions that Clients use to convey additional information to the Aggregator.  Some extensions might be intended for all Aggregators; others may only be intended for a specific Aggregator.  (For example, a DAP deployment might use some out-of-band mechanism for an Aggregator to verify that Reports come from authenticated Clients.  It will likely be useful to bind the extension to the input share via HPKE encryption.) </ins>  <ins> Each extension is a tag-length encoded value of the following form: Field "extension_type" indicates the type of extension, and </ins> "extension_data" contains information specific to the extension. <ins> Extensions are mandatory-to-implement: If an Aggregator receives a Report containing an extension it does not recognize, then it MUST reject the Report.  (See early-input-share-validation for details.) </ins> 4.3.4. The contents of each input share must be kept confidential from 4.4.1.3. Each report share has a corresponding task ID, report metadata  <ins> (report ID and, timestamp), the public share sent to each Aggregator, and the recipient's encrypted input share.  Let "task_id", "metadata", "public_share", and "encrypted_input_share" denote these values, respectively.  Given these values, an aggregator decrypts the input share as follows.  First, the aggregator looks up the HPKE config and corresponding secret key indicated by </ins> "encrypted_input_share.config_id".  If not found, then it marks the report share as invalid with the error "hpke_unknown_config_id". Otherwise, it constructs an "InputShareAad" message from "task_id", the aggregator ("0x02" for the leader and "0x03" for the helper).  If decryption fails, the aggregator marks the report share as invalid with the error "hpke_decrypt_error".  Otherwise, it outputs the  <ins> resulting PlaintextInputShare "plaintext_input_share".  The "OpenBase()" function is as specified in HPKE for the </ins> 4.4.1.4. "task_expiration" time, if so the Aggregator MAY mark the input share as invalid with the error "task_expired". <ins> Check if the PlaintextInputShare contains unrecognized extensions. If so, then the Aggregator MUST mark the input share as invalid with error "unrecognized_message". </ins> Finally, if an Aggregator cannot determine if an input share is valid. it MUST mark the input share as invalid with error "report_dropped".  This situation arises if, for example, the "0x01" for the helper); "agg_param" is the opaque aggregation parameter distributed to the aggregators by the collector; "public_share" is the public share generated by the client and  <ins> distributed to each aggregator; and "plaintext_input_share" is the aggregator's PlaintextInputShare. </ins> If either step fails, the aggregator marks the report as invalid with error "vdaf_prep_error".  Otherwise, the value "out" is interpreted