Draft: draft-ietf-ppm-dap

Commentary: Following from discussion in , this PR aims to only include the changes to request paths and message structures needed to absolve implementations of needing to partially parse messages to figure out how to parse the remainder . Further behavioral changes included in will be submitted as further PRs .
Paragraph (version B):
In this section, we discuss each of the resources and the messages
used to act on these resources.  A resource's path is resolved
relative to a server's endpoint to construct a resource URI.
Paragraph (version B):
"{role}" is one of the API endpoints in the task's
"aggregator_endpoints" (see task-configuration).  The remainder of
the path is resolved relative to the endpoint.
Paragraph (version B):
DAP resource identifiers are opaque byte strings, so any occurrence
of "{resource-id}" in a URL template (e.g., "{task-id}" or "{report-
id}") MUST be expanded to the URL-safe, unpadded Base 64
representation of the corresponding resource identifier, as specified
in sections 5 and 3.2 of RFC4648.
Paragraph (version A):
Clients retrieve the HPKE configuration from each aggregator by
sending an HTTP GET request to "[aggregator]/hpke_config", where
"[aggregator]" is the aggregator's endpoint URL, obtained from the
task parameters.  Clients MAY specify a query parameter "task_id"
when sending an HTTP GET request to
"[aggregator]/hpke_config?task_id=[task-id]", where "[task-id]" is
the task ID obtained from the task parameters, encoded in Base 64
with URL and filename safe alphabet with no padding, as specified in
sections 5 and 3.2 of RFC4648.  If the aggregator does not recognize
the task ID, then it MUST abort with error "unrecognizedTask".
Paragraph (version B):
Clients retrieve the HPKE configuration from each aggregator by
sending an HTTP GET request to "{aggregator}/hpke_config".  Clients
MAY specify a query parameter "task_id" whose value is the task ID
whose HPKE configuration they want.  If the aggregator does not
recognize the task ID, then it MUST abort with error
"unrecognizedTask".
Paragraph (version A):
A report ID used by the Aggregators to ensure the report appears
in at most one batch.  (See input-share-validation.)  The Client
MUST generate this by generating 16 random bytes using a
cryptographically secure random number generator.
Paragraph (version A):
A timestamp representing the time at which the report was
generated.  Specifically, the "time" field is set to the number of
seconds elapsed since the start of the UNIX epoch.  The client
SHOULD round this value down to the nearest multiple of
"time_precision" in order to ensure that that the timestamp cannot
be used to link a report back to the Client that generated it.
Paragraph (version B):
Clients upload reports by using an HTTP PUT to "{leader}/tasks/{task-
id}/reports", where "{leader}" is the first entry in the task's
aggregator endpoints.
Paragraph (version B):
"report_metadata" is public metadata describing the report.
Paragraph (version B):
"report_id" is used by the Aggregators to ensure the report
appears in at most one batch (see input-share-validation).  The
Client MUST generate this by generating 16 random bytes using a
cryptographically secure random number generator.
Paragraph (version B):
"public_share" is the public share output by the VDAF sharding
algorithm.  Note that the public share might be empty, depending
on the VDAF.  For example, Prio3 has an empty public share, but
Poplar1 does not.  See VDAF.
Paragraph (version B):
"encrypted_input_shares" is the encrypted input shares for each of
the Aggregators.
Paragraph (version A):
The leader responds to well-formed requests to "[leader]/upload" with
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.
Paragraph (version B):
The leader responds to well-formed requests with HTTP status code 201
Created.  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 201 Created.
Paragraph (version A):
The ID of the task for which the reports will be aggregated.
Paragraph (version A):
The aggregation job ID.
Paragraph (version A):
Let "[aggregator]" denote the helper's API endpoint.  The leader
sends a POST request to "[aggregator]/aggregate" with its
AggregateInitializeReq message as the payload.  The media type is
"application/dap-aggregate-initialize-req".
Paragraph (version A):
Each helper begins their portion of the aggregate initialization
phase with the set of candidate report shares obtained in an
"AggregateInitializeReq" message from the leader.  It attempts to
recover and validate the corresponding input shares similar to the
leader, and eventually returns a response to the leader carrying a
VDAF-specific message for each report share.
Paragraph (version B):
Let "{aggregator}" denote the helper's API endpoint.  The leader
sends a PUT request to "{aggregator}/tasks/{task-
id}/aggregation_jobs/{aggregation-job-id}" with its
"AggregationJobInitReq" message as the payload.  The media type is
"application/dap-aggregation-job-init-req".
Paragraph (version B):
Each helper begins their portion of the aggregate initialization
phase with the set of candidate report shares obtained in an
"AggregationJobInitReq" message from the leader.  It attempts to
recover and validate the corresponding input shares similar to the
leader, and eventually returns a response to the leader carrying a
VDAF-specific message for each report share.
Paragraph (version A):
The message is a sequence of PrepareStep values, the order of which
matches that of the ReportShare values in
"AggregateInitializeReq.report_shares".  Each report that was marked
as invalid is assigned the PrepareStepResult "failed".  Otherwise,
the PrepareStep is either marked as continued with the output
"prep_msg", or is marked as finished if the VDAF preparation process
is finished for the report share.
Paragraph (version A):
The helper's response to the leader is an HTTP status code 200 OK
whose body is the AggregateInitializeResp and media type is
"application/dap-aggregate-initialize-resp".
Paragraph (version A):
Upon receipt of a helper's AggregateInitializeResp message, the
leader checks that the sequence of PrepareStep messages corresponds
to the ReportShare sequence of the AggregateInitializeReq.  If any
message appears out of order, is missing, has an unrecognized report
ID, or if two messages have the same report ID, then the leader MUST
abort with error "unrecognizedMessage".
Paragraph (version B):
The message is a sequence of PrepareStep values, the order of which
matches that of the ReportShare values in
"AggregationJobInitReq.report_shares".  Each report that was marked
as invalid is assigned the "PrepareStepState" "failed".  Otherwise,
the "PrepareStep" is either marked as continued with the output
"prep_msg", or is marked as finished if the VDAF preparation process
is finished for the report share.
Paragraph (version B):
On success, the helper responds to the leader with HTTP status code
201 Created and a body consisting of the "AggregationJob", with media
type "application/dap-aggregation-job".
Paragraph (version B):
Upon receipt of a helper's "AggregationJob" message, the leader
checks that the sequence of "PrepareStep" messages corresponds to the
"ReportShare" sequence of the "AggregationJobInitReq".  If any
message appears out of order, is missing, has an unrecognized report
ID, or if two messages have the same report ID, then the leader MUST
abort with error "unrecognizedMessage".
Paragraph (version A):
For each aggregator endpoint "[aggregator]" in
"AggregateContinueReq.task_id"'s parameters except its own, the
leader sends a POST request to "[aggregator]/aggregate" with
AggregateContinueReq as the payload and the media type set to
"application/dap-aggregate-continue-req".
Paragraph (version B):
The Leader then sends a POST request to the aggregation job URI used
during initialization (see leader-init).  The body is an
"AggregationJob" message (see aggregation-helper-init) containing the
"PrepareStep"s.  The media type is set to "application/dap-
aggregation-job".
Paragraph (version A):
The order of AggregateContinueResp.prepare_steps MUST match that of
the PrepareStep values in "AggregateContinueReq.prepare_steps".  The
helper's response to the leader is an HTTP status code 200 OK whose
body is the AggregateContinueResp and media type is "application/dap-
aggregate-continue-resp".  The helper then awaits the next message
from the leader.
Paragraph (version B):
If successful, the helper responds to the leader with HTTP status 200
OK, media type "application/dap-aggregation-job" and a body
consisting of an "AggregationJob" (see aggregation-helper-init)
compiled from the stepped "PrepareStep"s.  The order of the steps
MUST match that of the "PrepareStep" values in the leader's
"AggregationJob".  The helper then awaits the next message from the
leader.
Paragraph (version A):
"task_id", the DAP task ID.  If the Leader does not recognize the
task ID, it MUST abort with error "unrecognizedTask".
Paragraph (version A):
"agg_param", an aggregation parameter for the VDAF being executed.
This is the same value as in "AggregateInitializeReq" (see leader-
init).
Paragraph (version B):
This ID MUST be unique within the context of the corresponding DAP
task.  It is RECOMMENDED that this be set to a random string output
by a cryptographically secure pseudorandom number generator.
Paragraph (version B):
"agg_param", an aggregation parameter for the VDAF being executed.
This is the same value as in "AggregationJobInitReq" (see leader-
init).
Paragraph (version A):
Depending on the VDAF scheme and how the leader is configured, the
leader and helper may already have prepared a sufficient number of
reports satisfying the query and be ready to return the aggregate
shares right away, but this cannot be guaranteed.  In fact, for some
VDAFs, it is not be possible to begin preparing inputs until the
collector provides the aggregation parameter in the "CollectReq".
For these reasons, collect requests are handled asynchronously.
Paragraph (version A):
Upon receipt of a "CollectReq", the leader begins by checking that
the request meets the requirements of the batch parameters using the
procedure in batch-validation.  If so, it immediately sends the
collector a response with HTTP status 303 See Other and a Location
header containing a URI identifying the collect job that can be
polled by the collector, called the "collect job URI".
Paragraph (version A):
After receiving the response to its CollectReq, the collector makes
an HTTP GET request to the collect job URI to check on the status of
the collect job and eventually obtain the result.  If the collect job
is not finished yet, the leader responds with HTTP status 202
Accepted.  The response MAY include a Retry-After header field to
suggest a pulling interval to the collector.
Paragraph (version B):
Depending on the VDAF scheme and how the leader is configured, the
leader and helper may already have prepared a sufficient number of
reports satisfying the query and be ready to return the aggregate
shares right away, but this cannot be guaranteed.  In fact, for some
VDAFs, it is not be possible to begin preparing inputs until the
collector provides the aggregation parameter in the "CollectionReq".
For these reasons, collect requests are handled asynchronously.
Paragraph (version B):
Upon receipt of a "CollectionReq", the leader begins by checking that
it recognizes the task ID in the request path.  If not, it MUST abort
with error "unrecognizedTask".  Then, the leader verifies that the
request meets the requirements of the batch parameters using the
procedure in batch-validation.  If so, it immediately responds with
HTTP status 201.
Paragraph (version B):
After receiving the response to its "CollectionReq", the collector
makes an HTTP "POST" request to the collection job URI to check on
the status of the collect job and eventually obtain the result.  If
the collection job is not finished yet, the leader responds with HTTP
status 202 Accepted.  The response MAY include a Retry-After header
field to suggest a polling interval to the collector.
Paragraph (version A):
If obtaining aggregate shares fails, then the leader responds to
subsequent HTTP GET requests to the collect job URI with an HTTP
error status and a problem document as described in errors.
Paragraph (version A):
The collector can send an HTTP DELETE request to the collect job URI,
to which the leader MUST respond with HTTP status 204 No Content.
The leader MAY respond with HTTP status 204 No Content for requests
to a collect job URI which has not received a DELETE request, for
example if the results have been deleted due to age.  The leader MUST
respond to subsequent requests to the collect job URI with HTTP
status 204 No Content.
Paragraph (version B):
If obtaining aggregate shares fails, then the leader responds to
subsequent HTTP POST requests to the collection job with an HTTP
error status and a problem document as described in errors.
Paragraph (version B):
The Leader MAY respond with HTTP status 204 No Content to requests to
a collection job if the results have been deleted.
Paragraph (version B):
The collector can send an HTTP DELETE request to the collection job,
which indicates to the leader that it can abandon the collection job
and discard all state related to it.
Paragraph (version B):
The reason we use a POST instead of a GET to poll the state of a
collection job is because of the fixed-size query mode (see fixed-
size-query).  Collectors may make a query against the current batch,
and it is the Leader's responsibility to keep track of what batch is
current for some task.  Polling a collection job is the only point at
which it is safe for the Leader to change its current batch, since it
constitutes acknowledgement on the Collector's part that it received
the response to some previous PUT request to the collection jobs
resource.
Paragraph (version B):
This means that polling a collection job can have the side effect of
changing the current batch in the Leader, and thus using a GET is
inappropriate.
Paragraph (version A):
The DAP task ID.  If the Helper does not recognize the task ID, it
MUST abort with error "unrecognizedTask".
Paragraph (version A):
To handle the leader's request, the helper first ensures that the
request meets the requirements for batch parameters following the
procedure in batch-validation.
Paragraph (version B):
To handle the leader's request, the helper first ensures that it
recognizes the task ID in the request path.  If not, it MUST abort
with error "unrecognizedTask".  The helper then verifies that the
request meets the requirements for batch parameters following the
procedure in batch-validation.
Paragraph (version A):
After receiving the helper's response, the leader uses the
HpkeCiphertext to respond to a collect request (see collect-flow).
Paragraph (version A):
Before completing the collect request, the leader also computes its
own aggregate share "agg_share" by aggregating all of the prepared
output shares that fall within the batch interval.  Finally, it
encrypts it under the collector's HPKE public key as described in
aggregate-share-encrypt.
Paragraph (version B):
After receiving the helper's response, the leader uses the
HpkeCiphertext to complete a collection job (see collect-flow).
Paragraph (version B):
Before completing the collection job, the leader also computes its
own aggregate share "agg_share" by aggregating all of the prepared
output shares that fall within the batch interval.  Finally, it
encrypts it under the collector's HPKE public key as described in
aggregate-share-encrypt.