jiebi/TextFlow huggingface dataset:
Original text:
helper, and so on. The leader responds to well-formed requests to "[leader]/upload" with <del> HTTP status code 200 OK and an empty body.  Malformed requests are handled as described in errors.  Clients SHOULD NOT upload the same measurement value in more than one report if the leader responds with HTTP status code 200 OK and an empty body. </del>  If the leader does not recognize the task ID, then it MUST abort with error "unrecognizedTask".

Reviewer comments:
Section 4.2.2: "Clients SHOULD NOT upload the same measurement value in more than one report if the leader responds with status 200 and an empty body.”" Is a non-empty body understood to signal an error condition based on some other context? What if the client got status 200 from the leader but a non-empty body? Should the client retry as this text suggests? I don't know enough about HTTP semantics to know for sure, but it seems like specifying an empty body here is unnecessary. It seems fine to specify that the leader should send an empty body for 200, but maybe be less strict on the consumption side and drop the empty body requirement?

Revised text:
helper, and so on. The leader responds to well-formed requests to "[leader]/upload" with  <ins> HTTP status code 200 OK.  Malformed requests are handled as described in errors.  Clients SHOULD NOT upload the same measurement value in more than one report if the leader responds with HTTP status code 200 OK. </ins> If the leader does not recognize the task ID, then it MUST abort with error "unrecognizedTask".
Original text:
The client MUST abort if any of the following happen for any HPKE config request: <del> the GET request failed or did not return a valid HPKE configuration; or </del>  <del> the HPKE configuration specifies a KEM, KDF, or AEAD algorithm the client does not recognize. </del>  Aggregators SHOULD use HTTP caching to permit client-side caching of this resource RFC5861.  Aggregators SHOULD favor long cache lifetimes

Reviewer comments:
The current text is out-dated. Update it to account for multiple HPKE configs returned by the Aggregator.

Revised text:
The client MUST abort if any of the following happen for any HPKE config request:  <ins> the GET request failed or did not return a valid HPKE config list; </ins>  <ins> the HPKE config list is empty; or no HPKE config advertised by the aggregator specifies a supported a KEM, KDF, or AEAD algorithm triple. </ins> Aggregators SHOULD use HTTP caching to permit client-side caching of this resource RFC5861.  Aggregators SHOULD favor long cache lifetimes
Original text:
be used to link a report back to the Client that generated it. To generate a report, the Client begins by sharding its measurement <del> into input shares as specified by the VDAF.  It then wraps each input share in the following structure: </del>  Field "extensions" is set to the list of extensions intended to be consumed by the given Aggregator.  (See upload-extensions.)  Field the reports in sub-batches of 10.  Each sub-batch takes two round- trips to process. <del> [OPEN ISSUE: Should there be an indication of whether a given aggregate request is a continuation of a previous sub-batch?] </del> The aggregation flow can be thought of as having three phases for transforming each valid input report share into an output share: removes it from the candidate report set and does not process it further. <del> If the type is "finished", then the leader aborts with "unrecognizedMessage".  If the type is "continued", then the leader </del>  proceeds as follows. Let "leader_outbound" denote the leader's prepare message and

Reviewer comments:
This PR includes several text cleanups previously folded into : The upload section explicitly describes the call to An obsolete TODO in the aggregation section is removed Text that incorrectly instructed leaders to abort if the helper finishes aggregation is corrected.

Revised text:
be used to link a report back to the Client that generated it. To generate a report, the Client begins by sharding its measurement  <ins> into input shares and the public share using the VDAF's sharding algorithm (VDAF): [TODO: in VDAF-04, "measurement_to_input_shares" will take a nonce argument, for which we will use the report ID #394] The Client then wraps each input share in the following structure: </ins> Field "extensions" is set to the list of extensions intended to be consumed by the given Aggregator.  (See upload-extensions.)  Field the reports in sub-batches of 10.  Each sub-batch takes two round- trips to process.  The aggregation flow can be thought of as having three phases for transforming each valid input report share into an output share: removes it from the candidate report set and does not process it further.  <ins> If the type is "finished" and the Leader's preparation of this report share is also finished, then the report share is aggregated and can now be collected (see collect-flow).  If the Leader is not finished, then the report cannot be processed further and MUST be removed from the candidate set. If the Helper's "PrepareStep" is of type "continued", then the Leader </ins> proceeds as follows. Let "leader_outbound" denote the leader's prepare message and
Original text:
The number of reports included in the batch.  The vector of encrypted aggregate shares.  They MUST appear in the same order as the aggregator endpoints list of the task parameters.

Reviewer comments:
The Leader now informs the Collector of what time interval is spanned by the reports aggregated into a collection, regardless of the query type. This is particularly useful for fixed size tasks as otherwise a Collector can only guess at the report times based on the timing of collection requests, but also useful in time interval tasks since the aggregated reports could span a smaller interval that what was requested (e.g., if the collector requested a one hour time interval, but reports only arrived during minutes 30-40 of that hour).
, the results of an aggregation are presented to the collector as: where is the encrypted form of . In the case of a time interval task, the collector will have explicitly requested collection over some interval of time, but in the case of a fixed size task, that aggregate result will have been compiled from a set of reports chosen by the leader. So the collector can only infer that the reports are from no later than when the collect request came in and no sooner than when the collector got the previous batch. DAP should explicitly tell the collector what time interval is covered by a collected batch.
One way to do this would be to amend . , it is defined as: We could add an to the case. However that is awkward because is also used in , so we have to make sure that there's something cogent the leader could put there. Another, simpler choice is to simply add an field to , but the downside there is that this information isn't useful in the time interval case, because the collector already knows what time interval it queried over.
I'm cool with adding an with the minimum and maximum timestamp of all reports in the batch. I think overloading is not the right approach, however, since this is meant to "partially determine" a batch of reports, where as the interval in our case is strictly informational. Unrelated follow question: if we define to be "the minimum and maximum timestamp of reports in the batch" then it's possible that . I think this is OK, and might even be useful.
+1 to not including an in ; instead, I think it should be placed directly in .
Chris' point that the interval in could be tighter than what was in is compelling. I also now think we should put the in (or, well, ). I'll draft this change and circulate it to the WG this week, as I would like to include it in draft-04, which already includes a bunch of message definition changes.

Revised text:
The number of reports included in the batch. <ins> The smallest interval of time that contains the timestamps of all reports included in the batch, such that the interval's start and duration are both multiples of the task's "time_precision" parameter.  Note that in the case of a "time_interval" type query (see query), this interval can be smaller than the one in the corresponding "CollectionReq.query". </ins> The vector of encrypted aggregate shares.  They MUST appear in the same order as the aggregator endpoints list of the task parameters.
Original text:
BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. <del> The following terms are used: </del> This document uses the presentation language of RFC8446 to define messages in the DAP protocol.  Encoding and decoding of these messages as byte strings also follows RFC8446.

Reviewer comments:
Based on . Update the definitions to align better with terminology in the VDAF draft. Also, add "aggregation paramter" and "public share".

Revised text:
BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here.  This document uses the presentation language of RFC8446 to define messages in the DAP protocol.  Encoding and decoding of these messages as byte strings also follows RFC8446.
Original text:
After stepping each state, the Helper advances its aggregation job to the Leader's "AggregationJobContinueReq.round".  If the "round" in the Leader's request is equal to the Helper's current round (i.e., this is not the first time the Leader has sent this request), then the Helper responds with the current round's

Reviewer comments:
During implementation of round skew recovery in Janus ([1]), we noticed that the specification is unclear about what the helper should do if . This commit clarifies that this value is illegal and should be rejected. [1]: URL After handling , the helper's aggregation job will be on round 0, because the helper is waiting for the leader to send it the first-round broadcast prepare message, with which helper will advance to round 1. So before this commit, the applicable statement in the text was: Which means the helper would have to retransmit its first-round prepare shares, which it had previously sent in response to . This is implementable but weird: if the leader dropped the response to , then it should recover by re-sending it (I just wasted months of my life making sure that PUT to an aggregation job is idempotent). It seems simpler to me to just forbid round to be 0.

Revised text:
After stepping each state, the Helper advances its aggregation job to the Leader's "AggregationJobContinueReq.round". <ins> If the "round" in the Leader's request is 0, then the Helper MUST abort with an error of type "unrecognizedMessage". </ins> If the "round" in the Leader's request is equal to the Helper's current round (i.e., this is not the first time the Leader has sent this request), then the Helper responds with the current round's
Original text:
04: <del> Resource oriented HTTP API. (#278, #398, #400) (*) </del>  <del> Clarify security requirements for choosing VDAF verify key (#407, #411). </del>  <del> Clients must provide nonce and random input when sharding inputs. (#394, #425) (*) </del>  <del> Collection message now includes interval of time spanned by constituent reports. (#397, #403) (*) </del>  Update share validation requirements based on latest security analysis. (#408, #410)

Reviewer comments:
We need for this change to make sense.
DAP-04 will need some routine changes: [x] Update version tags for HPKE to () [x] Bump VDAF-03 to 05 () [x] Update change log () [x] Run spell check ()

Revised text:
04:  <ins> Introduce resource oriented HTTP API. (#278, #398, #400) (*) </ins>  <ins> Clarify security requirements for choosing VDAF verify key. (#407, #411) </ins>  <ins> Require clients to provide nonce and random input when sharding inputs. (#394, #425) (*) </ins>  <ins> Add interval of time spanned by constituent reports to Collection message.  (#397, #403) (*) </ins> Update share validation requirements based on latest security analysis. (#408, #410)
Original text:
"encrypted_agg_share" computed above. After receiving the Helper's response, the Leader uses the <del> HpkeCiphertext to finialize a collection job (see collect- </del>  finalization). Once an AggregateShareReq has been issued for the batch determined by

Reviewer comments:
DAP-04 will need some routine changes: [x] Update version tags for HPKE to () [x] Bump VDAF-03 to 05 () [x] Update change log () [x] Run spell check ()

Revised text:
"encrypted_agg_share" computed above. After receiving the Helper's response, the Leader uses the  <ins> HpkeCiphertext to finalize a collection job (see collect- </ins> finalization). Once an AggregateShareReq has been issued for the batch determined by
Original text:
a particular button, a client could report clicks when none occurred. <del> Input: The original data emitted by a client, before any encryption or secret sharing scheme is applied.  This may include multiple measurements. </del>  Input share: one of the shares output by feeding an input into a secret sharing scheme.  Each share is to be transmitted to one of fails.  For example, if the input is meant to be a bit vectors, then "[2, 1, 0]" is invalid.  Leader: A distinguished aggregator that coordinates input validation and data collection. Proof share: A share of a proof, used by an aggregator during the input-validation protocol. <del> Measurement: A single value (e.g., a count) being reported by a client.  Multiple measurements may be grouped into a single protocol input. </del>  2.

Reviewer comments:
The design document discusses "reports" which are a group of measurements being submitted to a DPA instantiation. There should be an entry in the "Terminology" section that explicitly defines a report and how it relates to "measurements" and "inputs".
Thanks for putting the list back in alphabetical order, too!

Revised text:
a particular button, a client could report clicks when none occurred.  <ins> Input: The measurement (or measurements) emitted by a client, before any encryption or secret sharing scheme is applied. </ins> Input share: one of the shares output by feeding an input into a secret sharing scheme.  Each share is to be transmitted to one of fails.  For example, if the input is meant to be a bit vectors, then "[2, 1, 0]" is invalid. <ins> Measurement: A single value (e.g., a count) being reported by a client.  Multiple measurements may be grouped into a single protocol input. </ins> Leader: A distinguished aggregator that coordinates input validation and data collection. Proof share: A share of a proof, used by an aggregator during the input-validation protocol.  <ins> Report: Uploaded to the leader from the client.  A report contains the secret-shared and encrypted input and proof. </ins> 2.
Original text:
is a principle, 2^b-th root of unity (i.e., g^(s*2^b) = 1), where g is the generator of the multiplicative subgroup.  This fact allows us to quickly evaluate and interpolate polynomials at <del> 2^a-th roots of unity for any 1 <= a <= b.  Note that b imposes n </del>  upper bound on the size of proofs, so it should be large enough to accommodate all foreseeable use cases.  Something like b >= 20 is probably good enough.

Reviewer comments:
Removes the old Prio text, which by now is out-of-date. Addresses by changing the criteria.
The current criteria: Criterion (3) doesn't seem that important to me any more. I've yet to think of a use case where we want to do inversion in a validity circuit, or for which we don't have an alternative to FLT. In any case, we already can get pretty good performance with a more standard, generic algorithm: URL In addition to dropping (3), we should modify (2) by saying that needs to be large enough to accommodate the largest proofs we would ever generate. seems like a reasonable minimum. Finally, an important criterion to add would be to pick a field size that is as close as possible to a power of 2 without being larger. This helps to minimize the cost of rejection sampling when generating random field elements (see ).
Closing this since it's no longer relevant to this document. (It will be relevant to URL, however.)

Revised text:
is a principle, 2^b-th root of unity (i.e., g^(s*2^b) = 1), where g is the generator of the multiplicative subgroup.  This fact allows us to quickly evaluate and interpolate polynomials at  <ins> 2^a-th roots of unity for any 1 <= a <= b.  Note that b imposes an </ins> upper bound on the size of proofs, so it should be large enough to accommodate all foreseeable use cases.  Something like b >= 20 is probably good enough.
Original text:
3.3.1. <del> The client sends a POST request to "[leader]/upload_start" with the following message: The "task" field corresponds to the PA task for which a report will be generated. The leader responds to well-formed requests to "[leader]/upload_start" with status 200 and the following message: </del>  The message includes the PA parameters the client will use to generate its report.  It also includes a protocol-specific message,

Reviewer comments:
In we did away with the requirement for interaction between the client and leader. This PR resolves the issue by making the upload start request an idempotent GET.
Based on this week's design call (2021/7/7), "upload start" is likely going away altogether.

Revised text:
3.3.1.  <ins> The client sends a GET request to "[leader]/[version]/[task_id]/upload_start", where "[version] == PATask.version" and "[task_id] == PATask.id".  [TODO: Decide if adding the protocol version and task id to the URL is the right way to go.  Instead, we may want to make this a POST with a body that specifies the PATask.  (See issue#61.)] The leader respond with status 200 and the following message: </ins> The message includes the PA parameters the client will use to generate its report.  It also includes a protocol-specific message,
Original text:
We sometimes refer to this message as the _report_. The message contains the "task_id" of the previous request.  It also includes the time (in seconds since the beginning of UNIX time) at which the <del> report was generated.  The rest of the message consists of the encrypted input shares, each of which has the following structure: </del>  "config_id" is equal to "HpkeConfig.id", where "HpkeConfig" is the aggregator's key config. The helper handles each sub-request "PAAggregateSubReq" as follows. It first checks that checks that "PAAggregateSubReq.proto == PAParam.proto".  If not, it aborts and alerts the leader with <del> "incorrect protocol for sub-request".  Otherwise, It computes the </del>  HPKE context as where "sk" is its HPKE key and computes the body of the

Reviewer comments:
Partially addresses via clarification. Intra-batch replay attacks need more text.
NAME I was going to file a separate issue to discuss it. Stay tuned!
Currently, clients specify the report timestamp when uploading a report for a task. Presumably this timestamp is used to determine the window/batch in which a report is aggregated. Do we care if clients can spoof or change this timestamp to put reports into different batches? Since clients have no understanding of what batch their report goes into, and this is something that aggregators manage, perhaps we should drop this and let the aggregators figure out the report<>batch grouping?
Yes, that's the idea. We have no way of ensuring that the client doesn't lie about the timestamp. This "attack" is akin to the client just lying about the input itself (see ): It's something we can't do anything about, short of using a secure enclave on the client's machine. I think dealing with these problems is orthogonal to the spec here. On the other hand, it should our goal to allow an honest aggregator to ensure that each report appears in most one batch. The timestamp and batch window is intended to allow an honest aggregator to manage this reportbatch mapping efficiently, i.e., with minimal state between aggregate requests. Unless we can think of a better way, I think we should keep this in.
This issue is now subsumed by .
Might be worth adding an OPEN ISSUE to note the inter-batch replay attack we talked about yesterday.

Revised text:
We sometimes refer to this message as the _report_. The message contains the "task_id" of the previous request.  It also includes the time (in seconds since the beginning of UNIX time) at which the  <ins> report was generated.  This field is present to ensure that each report is included in at most one batch.  The rest of the message consists of the encrypted input shares, each of which has the following structure: </ins> "config_id" is equal to "HpkeConfig.id", where "HpkeConfig" is the aggregator's key config. The helper handles each sub-request "PAAggregateSubReq" as follows. It first checks that checks that "PAAggregateSubReq.proto == PAParam.proto".  If not, it aborts and alerts the leader with  <ins> "incorrect protocol for sub-request".  Otherwise, it computes the </ins> HPKE context as where "sk" is its HPKE key and computes the body of the
Original text:
We sometimes refer to this message as the _report_. The message contains the "task_id" of the previous request.  It also includes the <del> time (in seconds since the beginning of UNIX time) at which the report was generated.  This field is present to ensure that each report is included in at most one batch.  The rest of the message consists of the encrypted input shares, each of which has the following structure: </del>  "config_id" is equal to "HpkeConfig.id", where "HpkeConfig" is the aggregator's key config.

Reviewer comments:
Introduces and definitions, principally to make it more obvious that is a number of seconds.
Yeah, this is a nice improvement. I'd keep Time and Duration colocated so we can more clearly define in terms of the other.Good idea!

Revised text:
We sometimes refer to this message as the _report_. The message contains the "task_id" of the previous request.  It also includes the  <ins> time at which the report was generated.  This field is present to ensure that each report is included in at most one batch.  The rest of the message consists of the encrypted input shares, each of which has the following structure: </ins> "config_id" is equal to "HpkeConfig.id", where "HpkeConfig" is the aggregator's key config.
Original text:
the aggregators is malicious.  Differential privacy is a strong privacy definition, and protects users in extreme circumstances: Even if an adversary has prior knowledge of every input in a batch except <del> for one, that one record is still protected. </del>  8.6.

Reviewer comments:
Differential privacy can protect against attacks where a portion of the input data is known a priori, or when the size of a batch is small. This PR adds DP as an optional mitigation for PDA deployments and lists where it helps mitigate various threats. Additionally: Removes a false statement that revealing user input does not compromise other users' privacy. This is not necessarily the case (e.g. imagine if the batch size is 2 or if many users reveal their input). Removes a statement that clients revealing their inputs is outside the threat model (is this still relevant?)

Revised text:
the aggregators is malicious.  Differential privacy is a strong privacy definition, and protects users in extreme circumstances: Even if an adversary has prior knowledge of every input in a batch except  <ins> for one, that one record is still formally protected. [OPEN ISSUE: While parameters configuring the differential privacy noise (like specific distributions / variance) can be agreed upon out of band by the aggregators and collector, there may be benefits to adding explicit protocol support by encoding them into "PDAParams".] </ins> 8.6.