<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.43 (Ruby 2.6.10) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-apple-cfrg-vdaf-preamble-00" category="info" consensus="true" submissionType="IRTF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.35.0 -->
  <front>
    <title abbrev="PREAMBLE">The PREAMBLE VDAF</title>
    <seriesInfo name="Internet-Draft" value="draft-apple-cfrg-vdaf-preamble-00"/>
    <author initials="M." surname="Blunk" fullname="Mark Blunk">
      <organization>Apple Inc.</organization>
      <address>
        <email>mblunk@apple.com</email>
      </address>
    </author>
    <author initials="J." surname="Chen" fullname="Junye Chen">
      <organization>Apple Inc.</organization>
      <address>
        <email>junyec@apple.com</email>
      </address>
    </author>
    <author initials="P." surname="Jain" fullname="Palak Jain">
      <organization>Apple Inc.</organization>
      <address>
        <email>palak_jain@apple.com</email>
      </address>
    </author>
    <date year="2026" month="October" day="30"/>
    <area>IRTF</area>
    <workgroup>Crypto Forum</workgroup>
    <keyword>VDAF</keyword>
    <keyword>privacy-preserving aggregation</keyword>
    <keyword>block-sparse vectors</keyword>
    <abstract>
      <?line 87?>

<t>This document describes PREAMBLE, a two-party Verifiable Distributed Aggregation
Function (VDAF) for secure aggregation where each client holds a
large-dimensional vector that is <em>block-sparse</em>, meaning it is divided into
fixed-size blocks of which at most one is nonzero, and that nonzero block itself
satisfies a specified Fully Linear Proof (such as multihot, or a bounded L1 or
L2 norm).</t>
    </abstract>
    <note removeInRFC="true">
      <name>About This Document</name>
      <t>
        The latest revision of this draft can be found at <eref target="https://markblunk.github.io/draft-apple-cfrg-vdaf-preamble.html"/>.
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-apple-cfrg-vdaf-preamble/"/>.
      </t>
      <t>
        Discussion of this document takes place on the
        Crypto Forum Research Group mailing list (<eref target="mailto:cfrg@ietf.org"/>),
        which is archived at <eref target="https://mailarchive.ietf.org/arch/search/?email_list=cfrg"/>.
        Subscribe at <eref target="https://www.ietf.org/mailman/listinfo/cfrg/"/>.
      </t>
      <t>Source for this draft and an issue tracker can be found at
        <eref target="https://github.com/markblunk/draft-apple-cfrg-vdaf-preamble"/>.</t>
    </note>
  </front>
  <middle>
    <?line 96?>

<section anchor="introduction">
      <name>Introduction</name>
      <t>(RFC EDITOR: Remove this paragraph.) The source for this draft and the reference
code can be found at
https://github.com/markblunk/draft-apple-cfrg-vdaf-preamble.</t>
      <t>Prio3 <xref target="VDAF"/> is a widely deployed protocol used in the aggregation of
federated statistics: each client secret-shares a measurement (such as a binary
value or a vector of integers) among a set of Aggregators, who jointly verify
that it is well-formed before contributing its shares to an aggregate. PINE
<xref target="PINE"/> adapts this same approach to federated machine learning, where each
client's measurement is instead a gradient, and the Aggregators additionally
verify that its L2 norm is bounded, so that no one client's update can
disproportionately affect the trained model. In both constructions, the cost of
sharding, verifying, and aggregating a measurement scales linearly with its
dimension and can become impractical for vectors of large dimension, for
example, in the millions.</t>
      <t>Verifiable Distributed Point Functions (VDPF), as defined in <xref target="DP22"/> address
this issue for a different class of high-dimensional problems. Poplar1
(<xref section="8" sectionFormat="of" target="VDAF"/>) and Mastic <xref target="Mastic"/> use a similar functionality to let
a client secret-share a single point in a large domain (such as the location of
a <em>heavy hitter</em> input for Poplar1, or an input together with an associated
weight for Mastic), so that the verification and aggregation cost is governed by
the depth of the distributed point function's evaluation tree rather than by the
size of the domain itself.</t>
      <t>This document describes PREAMBLE, a two-party Verifiable Distributed Aggregation
Function (VDAF) that combines both ideas, following <xref target="PREAMBLE"/>, to aggregate
<em>block-sparse</em> vectors. Under this approach, a client's measurement, a vector of
large dimension, is divided into fixed-size blocks, at most one of which may be
nonzero.  PREAMBLE secret-shares this measurement without revealing which block
is nonzero or what it contains. It also provides a proof to verify that 1) at
most one block is nonzero; and 2) the contents of that block satify a property
that can be checked by an associated Fully Linear Proof (FLP) supplied as a
parameter (see <xref section="7" sectionFormat="of" target="VDAF"/>). Section <xref target="vdaf"/> specifies this generic
composition of VDPF and FLP, and <xref target="variants"/> instantiates it with concrete
FLPs.  PREAMBLE's communication cost scales with the block size and the depth of
the VDPF's tree (logarithmic in the number of blocks) rather than with the
dimension of the vector itself. The server-side cost of verification and
aggregation still scales linearly with the dimension.</t>
      <t>For example, consider a service that reports what kinds of photos people take at
popular locations. The map is divided into a grid of about a million (2^20)
tiles, and each tile is assigned a block of 100 counters, one per photo category
such as <em>sky</em>, <em>person</em>, or <em>recreation</em>, for a total dimension of roughly 100
million. Because the photos a client contributes in one collection period tend
to be taken in one geographic tile, its measurement touches a small number of
indices that could be contained in a small block: the block index identifies the
tile, and the block content records which categories appear there, which a
multihot FLP can limit to a small number. With PREAMBLE, the client's upload is
dominated by the 100-entry block and grows only logarithmically with the number
of blocks (the 20 levels of the VDPF tree). The Aggregators' verification work,
by contrast, still grows linearly with the dimension: they must evaluate the
VDPF down to every leaf and expand the secret shares of every coordinate there,
before summing the blocks elementwise and running the FLP on the sum.</t>
      <t>Another example comes from distributed model training, where each client
contributes a locally computed gradient. For models with millions or hundreds of
millions of parameters, the communication cost of sending a dense gradient is
prohibitive. Recent work shows while model training is global over all parameter
each individual client need only share the training result on a subset of the
parameters.  PREAMBLE suits this setting, especially when a regularity
condition, such as a bounded Euclidean (L2) norm, is also enforced on the
nonzero block.</t>
    </section>
    <section anchor="conventions">
      <name>Conventions and Definitions</name>
      <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
"SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/>
when, and only when, they appear in all capitals, as shown here.</t>
      <ul spacing="normal">
        <li>
          <t>Clients, Aggregators, and Collectors from <xref section="3" sectionFormat="of" target="VDAF"/>.</t>
        </li>
        <li>
          <t>Auxiliary functions from <xref section="2" sectionFormat="of" target="VDAF"/>.</t>
        </li>
      </ul>
      <table anchor="aux-functionalities">
        <name>Auxiliary functionalities</name>
        <thead>
          <tr>
            <th align="left">Functionality</th>
            <th align="left">Type</th>
            <th align="left">Definition</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td align="left">
              <tt>concat</tt></td>
            <td align="left">Function</td>
            <td align="left">Section 2</td>
          </tr>
          <tr>
            <td align="left">
              <tt>front</tt></td>
            <td align="left">Function</td>
            <td align="left">Section 2</td>
          </tr>
          <tr>
            <td align="left">
              <tt>to_be_bytes</tt></td>
            <td align="left">Function</td>
            <td align="left">Section 2</td>
          </tr>
          <tr>
            <td align="left">
              <tt>xor</tt></td>
            <td align="left">Function</td>
            <td align="left">Section 2</td>
          </tr>
          <tr>
            <td align="left">
              <tt>zeros</tt></td>
            <td align="left">Function</td>
            <td align="left">Section 2</td>
          </tr>
        </tbody>
      </table>
      <ul spacing="normal">
        <li>
          <t>Finite fields from <xref section="6.1" sectionFormat="of" target="VDAF"/>.</t>
        </li>
      </ul>
      <table anchor="field-functionalities">
        <name>Finite field functionalities</name>
        <thead>
          <tr>
            <th align="left">Functionality</th>
            <th align="left">Type</th>
            <th align="left">Definition</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td align="left">
              <tt>field.zeros</tt></td>
            <td align="left">Class Method</td>
            <td align="left">Section 6.1</td>
          </tr>
          <tr>
            <td align="left">
              <tt>vec_add</tt></td>
            <td align="left">Function</td>
            <td align="left">Section 6.1.1</td>
          </tr>
          <tr>
            <td align="left">
              <tt>vec_sub</tt></td>
            <td align="left">Function</td>
            <td align="left">Section 6.1.1</td>
          </tr>
          <tr>
            <td align="left">
              <tt>vec_neg</tt></td>
            <td align="left">Function</td>
            <td align="left">Section 6.1.1</td>
          </tr>
        </tbody>
      </table>
      <ul spacing="normal">
        <li>
          <t>Extendable-Output Functions (XOFs) from <xref section="6.2" sectionFormat="of" target="VDAF"/>.</t>
        </li>
      </ul>
      <table anchor="xof-functionalities">
        <name>XOF functionalities</name>
        <thead>
          <tr>
            <th align="left">Functionality</th>
            <th align="left">Type</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td align="left">
              <tt>XofTurboShake128</tt></td>
            <td align="left">Constructor</td>
          </tr>
          <tr>
            <td align="left">
              <tt>xof.next</tt></td>
            <td align="left">Instance Method</td>
          </tr>
          <tr>
            <td align="left">
              <tt>xof.derive_seed</tt></td>
            <td align="left">Class Method</td>
          </tr>
          <tr>
            <td align="left">
              <tt>xof.expand_into_vec</tt></td>
            <td align="left">Class Method</td>
          </tr>
          <tr>
            <td align="left">
              <tt>xof.SEED_SIZE</tt></td>
            <td align="left">Class Attribute</td>
          </tr>
        </tbody>
      </table>
      <section anchor="dst">
        <name>Domain Separation</name>
        <t>Each invocation of an XOF is initialized with a domain separation tag built by
<tt>dst_alg()</tt> below, which encodes the version of this document, an algorithm
class byte, the 4-byte PREAMBLE algorithm identifier (<xref section="5" sectionFormat="of" target="VDAF"/>),
and a 2-byte code identifying how the XOF output is used.</t>
        <t>The version of this document is a byte denoted <tt>VERSION</tt>. Its value SHALL be
<tt>0</tt>. The algorithm class byte is denoted <tt>ALG_CLASS</tt> and SHALL be <tt>0</tt>.</t>
        <ul empty="true">
          <li>
            <t>NOTE We'll bump <tt>VERSION</tt> whenever we publish a draft with incompatible
changes from the previous draft.</t>
          </li>
        </ul>
        <t>Algorithms in the remainder use the following helper:</t>
        <sourcecode type="python"><![CDATA[
def dst_alg(usage: int, algorithm_id: int, ctx: bytes) -> bytes:
    assert usage in range(14)
    assert algorithm_id in range(2 ** 32)
    return byte(VERSION) \
        + byte(ALG_CLASS) \
        + to_be_bytes(algorithm_id, 4) \
        + to_be_bytes(usage, 2) \
        + ctx
]]></sourcecode>
        <t><xref target="dst-usage"/> lists the usage codes referenced in the remainder of this
document. Codes <tt>2</tt>-<tt>7</tt> are reused, unmodified, from Prio3's own domain
separation scheme (<xref section="7.2" sectionFormat="of" target="VDAF"/>); codes <tt>11</tt>-<tt>13</tt> are defined by
this document. Prio3's code <tt>1</tt> (<tt>USAGE_MEAS_SHARE</tt>) is not used: PREAMBLE has
no measurement share, because the FLP's encoded measurement is exactly the VDPF
block (<xref target="overview"/>). Codes <tt>3</tt>, <tt>6</tt>, and <tt>7</tt> are derived only if
<tt>flp.JOINT_RAND_LEN &gt; 0</tt>. Codes <tt>8</tt>-<tt>10</tt> are RESERVED for future use and are not
derived by this document.</t>
        <table anchor="dst-usage">
          <name>XOF usage codes</name>
          <thead>
            <tr>
              <th align="left">Code</th>
              <th align="left">Usage</th>
              <th align="left">Reused from Prio3?</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td align="left">2</td>
              <td align="left">
                <tt>USAGE_PROOF_SHARE</tt>: expanding a proof-share seed</td>
              <td align="left">yes</td>
            </tr>
            <tr>
              <td align="left">3</td>
              <td align="left">
                <tt>USAGE_JOINT_RANDOMNESS</tt>: expanding the joint randomness</td>
              <td align="left">yes</td>
            </tr>
            <tr>
              <td align="left">4</td>
              <td align="left">
                <tt>USAGE_PROVE_RANDOMNESS</tt>: expanding the prover's randomness</td>
              <td align="left">yes</td>
            </tr>
            <tr>
              <td align="left">5</td>
              <td align="left">
                <tt>USAGE_QUERY_RANDOMNESS</tt>: expanding the verifier's query randomness</td>
              <td align="left">yes</td>
            </tr>
            <tr>
              <td align="left">6</td>
              <td align="left">
                <tt>USAGE_JOINT_RAND_SEED</tt>: deriving the joint randomness seed from its parts</td>
              <td align="left">yes</td>
            </tr>
            <tr>
              <td align="left">7</td>
              <td align="left">
                <tt>USAGE_JOINT_RAND_PART</tt>: deriving a party's joint randomness part</td>
              <td align="left">yes</td>
            </tr>
            <tr>
              <td align="left">8-10</td>
              <td align="left">RESERVED; not derived by this document</td>
              <td align="left">no</td>
            </tr>
            <tr>
              <td align="left">11</td>
              <td align="left">
                <tt>USAGE_EXTEND</tt>: expanding a VDPF internal-node seed (<xref target="vdpf-aux"/>)</td>
              <td align="left">no</td>
            </tr>
            <tr>
              <td align="left">12</td>
              <td align="left">
                <tt>USAGE_CONVERT</tt>: expanding a VDPF leaf-node seed (<xref target="vdpf-aux"/>)</td>
              <td align="left">no</td>
            </tr>
            <tr>
              <td align="left">13</td>
              <td align="left">
                <tt>USAGE_ONEHOT_CHECK</tt>: hashing the VDPF sparsity proofs together</td>
              <td align="left">no</td>
            </tr>
          </tbody>
        </table>
      </section>
    </section>
    <section anchor="overview">
      <name>PREAMBLE Overview</name>
      <t>An instance of PREAMBLE is parameterized by a <tt>dimension</tt> and a <tt>block_size</tt>
such that <tt>dimension = 2^depth * block_size</tt> for some <tt>depth &gt;= 0</tt>, and an
FLP-like circuit (see <xref target="flp"/>) that checks one block's contents. Here <tt>depth</tt> is
the length of a root-to-leaf path in the VDPF tree that carries the
measurement, not counting the root, so the vector has <tt>2^depth</tt> blocks, one per
leaf (<xref target="vdpf"/>). A Client's measurement is a <tt>dimension</tt>-length vector, divided
into blocks of <tt>block_size</tt> coordinates each, of which the Client designates
exactly one as nonzero:</t>
      <figure anchor="block-sparse-diagram">
        <name>A block-sparse measurement</name>
        <artwork><![CDATA[
+------+------+------+------+------+------+------+------+
|  0   |  0   |  B   |  0   |  0   |  0   |  0   |  0   |
+------+------+------+------+------+------+------+------+
   each block has `block_size` coordinates; `B` is the one nonzero
   block
]]></artwork>
      </figure>
      <t>PREAMBLE proves two things about this measurement:</t>
      <ol spacing="normal" type="1"><li>
          <t>Sparsity: at most one block is nonzero. This is proven by the
one-block-sparse VDPF of <xref target="vdpf"/>, which also secret-shares the
measurement's contents to the Aggregators.</t>
        </li>
        <li>
          <t>Block validity: the contents of the one nonzero block, a vector of
<tt>block_size</tt> coordinates, satisfy the property checked by the chosen FLP's
circuit (see <xref target="vdaf"/>). <xref target="variants"/> defines four instantiations of this,
PreambleCount, PreambleMultihotCountVec, PreambleSumVec, and
PreambleL1BoundSum.</t>
        </li>
      </ol>
      <t>The block is encoded with <tt>flp.encode()</tt> and secret-shared following the FLP.
Aggregation then proceeds as expected: each Aggregator locally sums, across
Clients, its share of every block's <em>aggregatable</em> form (the <tt>flp.OUTPUT_LEN</tt>
field elements that <tt>flp.truncate()</tt> maps an encoded block to) and the
Collector sums the Aggregators' shares and decodes each block. The aggregate
result (of size <tt>2^depth * flp.OUTPUT_LEN</tt>) is therefore one decoded result per
block, in block order.</t>
    </section>
    <section anchor="vdpf">
      <name>Specification of the One-Block-Sparse VDPF</name>
      <table anchor="vdpf-params">
        <name>One-block-sparse VDPF parameters</name>
        <thead>
          <tr>
            <th align="left">Parameter</th>
            <th align="left">Description</th>
            <th align="left">Value</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td align="left">
              <tt>KEY_SIZE: int</tt></td>
            <td align="left">the size of each VDPF key</td>
            <td align="left">
              <tt>XOF.SEED_SIZE</tt></td>
          </tr>
          <tr>
            <td align="left">
              <tt>NONCE_SIZE: int</tt></td>
            <td align="left">the size of the report nonce</td>
            <td align="left">
              <tt>16</tt></td>
          </tr>
          <tr>
            <td align="left">
              <tt>RAND_SIZE: int</tt></td>
            <td align="left">the number of random bytes consumed by <tt>gen()</tt></td>
            <td align="left">
              <tt>2 * KEY_SIZE</tt></td>
          </tr>
          <tr>
            <td align="left">
              <tt>PROOF_SIZE: int</tt></td>
            <td align="left">the size of the sparsity proof</td>
            <td align="left">
              <tt>32</tt></td>
          </tr>
          <tr>
            <td align="left">
              <tt>leaf_size: int</tt></td>
            <td align="left">the number of field elements carried per block</td>
            <td align="left">
              <tt>flp.MEAS_LEN</tt> (<xref target="vdaf"/>)</td>
          </tr>
          <tr>
            <td align="left">
              <tt>num_leaf_nodes: int</tt></td>
            <td align="left">the number of leaves in the bottom level of the tree</td>
            <td align="left">
              <tt>dimension / block_size</tt>, a power of 2</td>
          </tr>
          <tr>
            <td align="left">
              <tt>depth: int</tt></td>
            <td align="left">the length of a root-to-leaf path, not counting the root</td>
            <td align="left">
              <tt>num_leaf_nodes.bit_length() - 1</tt></td>
          </tr>
        </tbody>
      </table>
      <t>This section specifies a Verifiable Distributed Point Function for the
one-block-sparse functionality: the key generation algorithm (<xref target="vdpf-key-gen"/>)
takes one block's <em>encoded</em> form (a vector of <tt>leaf_size</tt>-many field elements,
as determined by the underlying FLP) together with a <tt>leaf_index</tt> identifying
which of the <tt>num_leaf_nodes</tt> leaves it belongs to, and produces Aggregators'
key shares. Evaluating those keys at every leaf (<xref target="vdpf-key-eval"/>) gives each
Aggregator <tt>leaf_size</tt>-many field elements and one sparsity proof per leaf;
combined across the two Aggregators, the field elements equal the original
encoded block at <tt>leaf_index</tt> and the zero vector at every other leaf, and the
proofs let the Aggregators jointly verify that this one-block-sparse shape
holds, all without either Aggregator learning <tt>leaf_index</tt> or the encoded block.</t>
      <t>The VDPF is agnostic to what the field elements of a block mean: it carries
<tt>flp.MEAS_LEN</tt> of them per block (<xref target="overview"/>).</t>
      <section anchor="vdpf-key-gen">
        <name>Key Generation</name>
        <t>The key generation algorithm is run by the Client. Its inputs are <tt>leaf_index:
int</tt> (an integer in <tt>[0, num_leaf_nodes)</tt> identifying which block is nonzero,
that is, the <em>path</em> through the tree, encoded as a bit tuple), <tt>values: list[F]</tt>
(the nonzero block's encoded contents), the report <tt>nonce</tt>, and <tt>RAND_SIZE</tt>
bytes of randomness. Its outputs are the VDPF-related portion of the public
share, denoted <tt>CorrectionWords</tt>, and two private input shares, one for each
Aggregator, each consisting of a seed.</t>
        <t>The object <tt>CorrectionWords</tt> carries one correction word per tree level plus two
additional correction words for the leaf level, each playing a different role in
making the two Aggregators' otherwise-independent seed trees agree at every node
off the path to <tt>leaf_index</tt>:</t>
        <ul spacing="normal">
          <li>
            <t>An <strong>Internal Correction Word</strong> (one per level) carries a single seed
correction word, applied identically to both children's expanded seeds, and
two separate control bit correction words, <tt>ctrl_bit_left</tt> and
<tt>ctrl_bit_right</tt>, one per child. The construction of these seeds and control
bits maintains the following invariant at each node: the two Aggregators'
seeds and control bits differ if and only if the node is on-path.  If an
Aggregator's control bit for the node being expanded is nonzero, it applies
the correction word for that level to the seeds and control bits of the node's
two children (<xref target="vdpf-aux"/>, <tt>eval_next_children()</tt>). At an off-path node the
two control bits are equal, so both Aggregators apply the correction or
neither does, and their seeds and control bits stay equal in every off-path
descendant. At an on-path node the two control bits differ, so exactly one
Aggregator applies the correction. The correction words are chosen so that the
off-path child ends up with equal seeds and control bits for both Aggregators,
while the on-path child keeps differing seeds and control bits.</t>
          </li>
          <li>
            <t>The <strong>Leaf Correction Word</strong> is a vector of <tt>leaf_size</tt> field elements. Added
into a leaf's field elements by whichever Aggregator has that leaf's control
bit set (<xref target="vdpf-aux"/>, <tt>eval_all()</tt>), it cancels out (both Aggregators apply
it, or neither does) at every leaf other than <tt>leaf_index</tt>, and makes the two
Aggregators' shares of the leaf at <tt>leaf_index</tt> sum to <tt>values</tt>.</t>
          </li>
          <li>
            <t>The <strong>Proof Correction Word</strong> does the analogous thing for the leaf-level
sparsity proof (<xref target="node-identity"/>): it makes the two Aggregators' proof shares
combine to the same value at every leaf except <tt>leaf_index</tt>, which is what
lets <xref target="verification"/> check one-block-sparsity without revealing <tt>leaf_index</tt>.</t>
          </li>
        </ul>
        <t>The wire-format encoding of these types is given in <xref target="msg-public-share"/>.</t>
        <sourcecode type="python"><![CDATA[
class InternalCorrectionWord:
    def __init__(self, seed_cw: bytes, ctrl_bit_left: bool,
                 ctrl_bit_right: bool):
        self.seed_cw = seed_cw
        self.ctrl_bit_left = ctrl_bit_left
        self.ctrl_bit_right = ctrl_bit_right

LeafCorrectionWord: TypeAlias = list[F]
ProofCorrectionWord: TypeAlias = bytes

class CorrectionWords(Generic[F]):
    def __init__(self,
                 internal_cws: list[InternalCorrectionWord],
                 leaf_cw: LeafCorrectionWord,
                 proof_cw: ProofCorrectionWord):
        self.internal_cws = internal_cws
        self.leaf_cw = leaf_cw
        self.proof_cw = proof_cw
]]></sourcecode>
        <t>The algorithm invokes the auxiliary functions <tt>extend()</tt> and
<tt>compute_leaf_level()</tt>, defined in <xref target="vdpf-aux"/>. It walks the tree from the root
toward <tt>leaf_index</tt>, maintaining the same seed/control-bit invariant as Mastic's
own key generation (<xref section="3.1" sectionFormat="of" target="Mastic"/>, informally): at every level,
exactly one of the two children the Client is <em>not</em> traveling toward gets a
correction word that, when applied by exactly one Aggregator, makes both
Aggregators' seeds and control bits agree off the path and disagree on the path.</t>
        <sourcecode type="python"><![CDATA[
def gen(self,
        leaf_index: int,
        values: list[F],
        ctx: bytes,
        nonce: bytes,
        rand: bytes,
        ) -> tuple[CorrectionWords[F], list[bytes]]:
    '''
    Returns this DPF's correction words (the VDPF-only slice of the
    public share: the correction word for each internal level and
    leaf level of the tree, plus the proof correction word), and the
    two initial seeds, one for each Aggregator. The public share's
    other field, `joint_rand_parts`, is computed separately by the
    caller, though it binds the encoded correction words returned
    here.
    '''
    if leaf_index < 0 or leaf_index >= self.num_leaf_nodes:
        raise ValueError("leaf_index out of range")
    if len(nonce) != self.NONCE_SIZE:
        raise ValueError("incorrect nonce size")
    if len(rand) != self.RAND_SIZE:
        raise ValueError("randomness has incorrect length")

    # Step 1: Initial seeds sent to leader and helper.
    initial_seeds = [rand[:self.KEY_SIZE], rand[self.KEY_SIZE:]]
    # Seeds that are updated in each level of the tree.
    seeds = initial_seeds.copy()
    # Step 2: Signal for each aggregator whether to apply correction
    # words.
    # We maintain the invariant such that:
    # - If a node is on path, ctrl[0] ^ ctrl[1] = 1.
    # - If a node is off path, ctrl[0] ^ ctrl[1] = 0.
    # Initially set the helper's index to be True, so helper applies
    # the correction word.
    ctrl_bits_initial = [False, True]
    # Compute the internal-level correction words sent to both
    # aggregators.
    internal_cws: list[InternalCorrectionWord] = []
    # Step 3: Loop through each internal level of the DPF tree.
    for i in range(self.depth):
        bit = bool((leaf_index >> (self.depth - 1 - i)) & 1)

        # Step 4: Expand PRG into seed and control bit for both
        # aggregators.
        (s0, t0) = self.extend(seeds[0], ctx, nonce)
        (s1, t1) = self.extend(seeds[1], ctx, nonce)

        # Steps 5 and 6: If the current level is a 1, we will
        # traverse the right child (`keep` set to 1).
        # Otherwise, traverse the left child (`keep` set to 0).
        (keep, lose) = (1, 0) if bit else (0, 1)

        # Steps 7, 8, 9: Compute the correction words for this
        # level's seed and control bit. Our goal is to maintain the
        # following invariant, after correction:
        #
        # * If evaluation is on path, then each aggregator will
        #   compute a different seed and their control bits will be
        #   secret shares of one.
        #
        # * If evaluation is off path, then the aggregators will
        #   compute the same seed and their control bits will be
        #   shares of zero.
        #
        # Implementation note: the index `lose` is
        # `leaf_index`-dependent.
        seed_cw = xor(s0[lose], s1[lose])
        ctrl_bits = [
            t0[0] ^ t1[0] ^ (not bit),
            t0[1] ^ t1[1] ^ bit,
        ]

        # Steps 10 and 11: Correct.
        #
        # Implementation note: the index `keep` is
        # `leaf_index`-dependent, as is `ctrl`.  If the control
        # bit is set, apply the correction words.
        if ctrl_bits_initial[0]:
            s0[keep] = xor(s0[keep], seed_cw)
            t0[keep] ^= ctrl_bits[keep]
        if ctrl_bits_initial[1]:
            s1[keep] = xor(s1[keep], seed_cw)
            t1[keep] ^= ctrl_bits[keep]

        # After correction, they become next level's seeds and
        # control bits.
        seeds[0] = s0[keep]
        seeds[1] = s1[keep]
        ctrl_bits_initial[0] = t0[keep]
        ctrl_bits_initial[1] = t1[keep]

        internal_cws.append(
            InternalCorrectionWord(
                seed_cw, ctrl_bits[0], ctrl_bits[1]))

    # Sample leader and helper's random field elements and also the
    # proofs for block sparsity from their seeds at the leaf level.
    # During generation, we use the full path which is leaf_index
    # (the block index).
    leaf_index_bytes = leaf_index.to_bytes(
        (self.depth + 7) // 8, byteorder='big')
    (w0, proof0) = self.compute_leaf_level(
        seeds[0], ctx, nonce + leaf_index_bytes)
    (w1, proof1) = self.compute_leaf_level(
        seeds[1], ctx, nonce + leaf_index_bytes)
    leaf_cw = vec_add(vec_sub(values, w0), w1)

    if ctrl_bits_initial[1]:
        leaf_cw = vec_neg(leaf_cw)
    proof_cw = xor(proof0, proof1)
    return (CorrectionWords(internal_cws, leaf_cw, proof_cw),
            initial_seeds)
]]></sourcecode>
      </section>
      <section anchor="vdpf-key-eval">
        <name>Key Evaluation</name>
        <t>The key evaluation algorithm is run independently by each Aggregator. Its inputs
are the report <tt>nonce</tt>, the Aggregator's ID (<tt>0</tt> for the first, <tt>1</tt> for the
second), the Aggregator's key (one of the two seeds output by <tt>gen()</tt>), the
Aggregator's initial control bit (<tt>0</tt> for one Aggregator, <tt>1</tt> for the other),
and the public share (consisting of the leaf correction word, proof correction
word, and internal correction words and control bits). Its outputs are the
Aggregator's share of every coordinate of the shared vector <tt>F</tt>, and one
sparsity proof for the leaf.</t>
        <sourcecode type="python"><![CDATA[
def eval_all(self,
             ctx: bytes,
             nonce: bytes,
             agg_id: int,
             initial_seed: bytes,
             initial_ctrl_bit: bool,
             cws: CorrectionWords[F],
             ) -> tuple[list[F], list[bytes]]:
    '''
    Evaluate the field elements expanded from the leaf nodes. Every
    leaf contributes its full `leaf_size` field elements, so the
    result has exactly `num_leaf_nodes * leaf_size` field elements.
    '''
    root_node = EvalNode(level=0, seed=initial_seed,
                         ctrl_bit=initial_ctrl_bit)
    if self.depth == 0:
        # Nothing to traverse, only need to expand the leaf node.
        internal_nodes = []
        leaf_nodes = [root_node]
    else:
        internal_nodes = [root_node]
        leaf_nodes = []
    # Run BFS on the tree.
    while len(internal_nodes) > 0:
        node = internal_nodes.pop(0)
        (left_child, right_child) = self.eval_next_children(
            ctx, nonce, node, cws.internal_cws)
        if node.level < self.depth - 1:
            internal_nodes.append(left_child)
            internal_nodes.append(right_child)
        else:
            leaf_nodes.append(left_child)
            leaf_nodes.append(right_child)

    assert len(leaf_nodes) == self.num_leaf_nodes
    field_elems: list[F] = []
    proofs: list[bytes] = []
    for leaf_node in leaf_nodes:
        leaf_index_bytes = leaf_node.leaf_index.to_bytes(
            (self.depth + 7) // 8, byteorder='big')
        (w, proof) = self.compute_leaf_level(
            leaf_node.seed, ctx, nonce + leaf_index_bytes)
        if leaf_node.ctrl_bit:
            w = vec_add(w, cws.leaf_cw)
            proof = xor(proof, cws.proof_cw)
        if agg_id == 1:
            # Helper negates its share.
            w = vec_neg(w)
        field_elems.extend(w)
        proofs.append(proof)
    return field_elems, proofs
]]></sourcecode>
      </section>
      <section anchor="node-identity">
        <name>Node Identity and the Leaf-Level Sparsity Proof</name>
        <t>Every leaf node's field elements and sparsity proof are sampled from an XOF
whose binder is <tt>nonce + leaf_index_bytes</tt>, that is, the report nonce
concatenated with the <em>encoding of that specific leaf's own index</em>
(<tt>compute_leaf_level()</tt>, <xref target="vdpf-aux"/>). This binds each leaf's output to its
identity within the tree. The concatenated sparsity proofs are hashed into a
one-hot check value, see (<xref target="verification"/>) for more details.</t>
      </section>
      <section anchor="vdpf-aux">
        <name>Auxiliary Functions</name>
        <sourcecode type="python"><![CDATA[
class EvalNode:
    def __init__(self, level: int, seed: bytes, ctrl_bit: bool,
                leaf_index: int = 0):
        self.level = level
        self.seed = seed
        self.ctrl_bit = ctrl_bit
        self.leaf_index = leaf_index

def eval_next_children(self,
                       ctx: bytes,
                       nonce: bytes,
                       node: EvalNode,
                       internal_cw_list:
                           list[InternalCorrectionWord],
                       ) -> tuple[EvalNode, EvalNode]:
    seed_cw = internal_cw_list[node.level].seed_cw
    ctrl_left_cw = internal_cw_list[node.level].ctrl_bit_left
    ctrl_right_cw = internal_cw_list[node.level].ctrl_bit_right
    (s, t) = self.extend(node.seed, ctx, nonce)
    if node.ctrl_bit:
        s[0] = xor(s[0], seed_cw)
        t[0] ^= ctrl_left_cw
        s[1] = xor(s[1], seed_cw)
        t[1] ^= ctrl_right_cw
    left_child = EvalNode(level=node.level + 1, seed=s[0],
                          ctrl_bit=t[0],
                          leaf_index=node.leaf_index << 1)
    right_child = EvalNode(level=node.level + 1, seed=s[1],
                           ctrl_bit=t[1],
                           leaf_index=(node.leaf_index << 1) | 1)
    return (left_child, right_child)
]]></sourcecode>
        <sourcecode type="python"><![CDATA[
def extend(self,
           seed: bytes,
           ctx: bytes,
           nonce: bytes,
           ) -> tuple[list[bytes], list[bool]]:
    '''
    Extend a seed into the seed and control bits for its left and
    right children in the tree.
    '''
    xof = self.xof(
        seed, dst_alg(USAGE_EXTEND, self.algorithm_id, ctx), nonce)
    s = [
        bytearray(xof.next(self.KEY_SIZE)),
        bytearray(xof.next(self.KEY_SIZE)),
    ]
    # Use the least significant bits as the control bit correction,
    # and then zero it out. This gives effectively 127 bits of
    # security, but reduces the number of AES calls needed by 1/3.
    t = [bool(s[0][0] & 1), bool(s[1][0] & 1)]
    s[0][0] &= 0xFE
    s[1][0] &= 0xFE
    return ([bytes(s[0]), bytes(s[1])], t)

def compute_leaf_level(self,
                       seed: bytes,
                       ctx: bytes,
                       nonce: bytes) -> tuple[list[F], bytes]:
    '''
    Compute the field elements and sparsity proof at a leaf node,
    expanded from the seed. `nonce` is the report nonce concatenated
    with the leaf's identity; see {{node-identity}}.
    '''
    xof = self.xof(
        seed, dst_alg(USAGE_CONVERT, self.algorithm_id, ctx), nonce)
    vals: list[F] = xof.next_vec(self.field, self.leaf_size)
    proof: bytes = xof.next(PROOF_SIZE)
    return (vals, proof)
]]></sourcecode>
      </section>
    </section>
    <section anchor="vdaf">
      <name>Specification of PREAMBLE</name>
      <t>As stated previously, an instance of PREAMBLE is determined by a <tt>dimension</tt>, a
<tt>block_size</tt>, and a validity circuit <tt>valid: Valid[FLPMeasurement, FLPResult,
F]</tt> that checks the contents of the one nonzero block: an <tt>FLPMeasurement</tt>,
which the circuit encodes into <tt>flp.MEAS_LEN</tt> field elements. PREAMBLE wraps the
circuit in Prio3's FLP construction (<xref target="VDAF"/>, based on <xref target="BBCGGI19"/>),
<tt>flp = FlpBBCGGI19(valid)</tt>.
PREAMBLE's Client measurement type is:</t>
      <sourcecode type="python"><![CDATA[
PreambleMeasurement: TypeAlias = tuple[
    tuple[bool, ...], FLPMeasurement]
]]></sourcecode>
      <t>A <tt>PreambleMeasurement</tt> is a <tt>(block_index, block_content)</tt> pair (<xref target="overview"/>):
<tt>block_index</tt> is the path (as a tuple of booleans, most significant bit first)
to the vector's one nonzero block, and <tt>block_content</tt> is that block's instance
of an <tt>FLPMeasurement</tt>. The chosen <tt>flp</tt> MUST accept a <tt>block_size</tt>-coordinate
block as its measurement; how <tt>FLPMeasurement</tt> is shaped, and hence how
<tt>block_size</tt> relates to <tt>flp.MEAS_LEN</tt> and <tt>flp.OUTPUT_LEN</tt>, is circuit-specific
and is fixed by each variant in <xref target="variants"/>. For a circuit that takes a
<tt>length</tt> parameter, such as <tt>SumVec</tt> or <tt>MultihotCountVec</tt> (<xref section="7.4" sectionFormat="of" target="VDAF"/>), <tt>block_size</tt> is that <tt>length</tt>.</t>
      <t>The aggregate result has type <tt>list[FLPResult]</tt>, where <tt>FLPResult</tt> is likewise
a type defined by the validity circuit of the underlying FLP: one <tt>FLPResult</tt>
per block, in block order. The size of this list is equal to <tt>num_leaf_nodes</tt>.</t>
      <t>The VDPF is instantiated over the same <tt>field</tt> as <tt>FLP</tt> with <tt>num_leaf_nodes =
dimension / block_size</tt> leaves and <tt>leaf_size = flp.MEAS_LEN</tt> field elements per
leaf, because the values it shares are the <em>encoded</em> block contents. This
instance of the VDPF is denoted <tt>vdpf</tt>. The length of an aggregate share
(<xref target="aggregation"/>) is</t>
      <sourcecode type="python"><![CDATA[
output_len = num_leaf_nodes * flp.OUTPUT_LEN
]]></sourcecode>
      <t>because each block contributes the <tt>flp.OUTPUT_LEN</tt> field elements its encoded
form truncates to.</t>
      <t>The XOF type in use is denoted <tt>xof</tt> (<xref target="variants"/> fixes a concrete choice).</t>
      <section anchor="flp">
        <name>Fully Linear Proof</name>
        <t>PREAMBLE checks the contents of the nonzero block with a Fully Linear Proof
(FLP) system <tt>flp</tt>, which is a parameter of the construction.  PREAMBLE uses
<tt>flp</tt> only through the FLP interface of <xref section="7.1" sectionFormat="of" target="VDAF"/>:</t>
        <table anchor="flp-functionalities">
          <name>FLP functionalities</name>
          <thead>
            <tr>
              <th align="left">Functionality</th>
              <th align="left">Type</th>
              <th align="left">Definition</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td align="left">
                <tt>flp.field</tt></td>
              <td align="left">Attribute</td>
              <td align="left">Section 7.1</td>
            </tr>
            <tr>
              <td align="left">
                <tt>flp.MEAS_LEN</tt></td>
              <td align="left">Attribute</td>
              <td align="left">Section 7.1</td>
            </tr>
            <tr>
              <td align="left">
                <tt>flp.OUTPUT_LEN</tt></td>
              <td align="left">Attribute</td>
              <td align="left">Section 7.1</td>
            </tr>
            <tr>
              <td align="left">
                <tt>flp.PROOF_LEN</tt></td>
              <td align="left">Attribute</td>
              <td align="left">Section 7.1</td>
            </tr>
            <tr>
              <td align="left">
                <tt>flp.VERIFIER_LEN</tt></td>
              <td align="left">Attribute</td>
              <td align="left">Section 7.1</td>
            </tr>
            <tr>
              <td align="left">
                <tt>flp.PROVE_RAND_LEN</tt></td>
              <td align="left">Attribute</td>
              <td align="left">Section 7.1</td>
            </tr>
            <tr>
              <td align="left">
                <tt>flp.QUERY_RAND_LEN</tt></td>
              <td align="left">Attribute</td>
              <td align="left">Section 7.1</td>
            </tr>
            <tr>
              <td align="left">
                <tt>flp.JOINT_RAND_LEN</tt></td>
              <td align="left">Attribute</td>
              <td align="left">Section 7.1</td>
            </tr>
            <tr>
              <td align="left">
                <tt>flp.prove</tt></td>
              <td align="left">Instance Method</td>
              <td align="left">Section 7.1</td>
            </tr>
            <tr>
              <td align="left">
                <tt>flp.query</tt></td>
              <td align="left">Instance Method</td>
              <td align="left">Section 7.1</td>
            </tr>
            <tr>
              <td align="left">
                <tt>flp.decide</tt></td>
              <td align="left">Instance Method</td>
              <td align="left">Section 7.1</td>
            </tr>
            <tr>
              <td align="left">
                <tt>flp.encode</tt></td>
              <td align="left">Instance Method</td>
              <td align="left">Section 7.1.1</td>
            </tr>
            <tr>
              <td align="left">
                <tt>flp.truncate</tt></td>
              <td align="left">Instance Method</td>
              <td align="left">Section 7.1.1</td>
            </tr>
            <tr>
              <td align="left">
                <tt>flp.decode</tt></td>
              <td align="left">Instance Method</td>
              <td align="left">Section 7.1.1</td>
            </tr>
          </tbody>
        </table>
        <t>In addition to implementing that interface, an FLP used with PREAMBLE MUST
satisfy the following:</t>
        <ol spacing="normal" type="1"><li>
            <t><tt>flp.field</tt> is the field over which the VDPF is instantiated (<xref target="vdaf"/>). The
VDPF secret-shares the encoded block, and each Aggregator queries the proof
directly on its share of it.</t>
          </li>
          <li>
            <t><tt>flp.truncate</tt> is linear. Each Aggregator applies it to its share of every
block, including the blocks whose shares sum to zero, and sums the results
into its output share (<xref target="verification"/>). Prio3 relies on the same property
when it truncates a measurement share (<xref section="7.2.2" sectionFormat="of" target="VDAF"/>).</t>
          </li>
        </ol>
        <t>The FLP specified in <xref section="7.3" sectionFormat="of" target="VDAF"/>, <tt>FlpBBCGGI19</tt>, implements this
interface for any validity circuit, so the requirements above restrict only the
choice of circuit. <xref target="variants"/> fixes the circuits for which this document
defines a PREAMBLE instantiation.</t>
        <t>The field <tt>flp.JOINT_RAND_LEN</tt> MAY be zero, as for a circuit such as Count that
uses no joint randomness. As in Prio3 (<xref section="7.2.1" sectionFormat="of" target="VDAF"/>), PREAMBLE then
omits the joint randomness machinery altogether: the Clients derive no blinds,
the Aggregators derive no joint randomness parts, and there is no joint
randomness seed to cross-check. The proof is unaffected. It is still generated,
secret-shared, and checked with <tt>flp.decide()</tt>, and <tt>flp.prove()</tt> and
<tt>flp.query()</tt> are invoked with an empty joint randomness. Everything in this
document that concerns joint randomness applies only when <tt>flp.JOINT_RAND_LEN &gt;
0</tt>, and <xref target="sharding"/>, <xref target="verification"/>, and <xref target="msg-serialization"/> say what
changes otherwise.</t>
        <ul empty="true">
          <li>
            <t>TODO When <tt>flp.JOINT_RAND_LEN &gt; 0</tt>, each part binds the nonce, the encoded
public share, and the VDPF seed. The public share and the VDPF seed determine
the Aggregator's share, so they take the place of the measurement share that
Prio3's and Mastic's parts bind alongside the nonce. This document does not
prove that binding them is equivalent, that is, that a Client cannot choose
its shares after seeing the joint randomness.</t>
          </li>
        </ul>
        <t>PREAMBLE's implementation of the VDAF interface (<xref section="5" sectionFormat="of" target="VDAF"/>) is
specified in the following sections.</t>
      </section>
      <section anchor="sharding">
        <name>Sharding</name>
        <t>The sharding algorithm takes the measurement, the report <tt>nonce</tt>, and sharding
randomness of length <tt>RAND_SIZE</tt>, defined below. Its output is a public share,
<tt>PreamblePublicShare</tt>, and a pair of input shares, <tt>PreambleInputShare</tt>, one for
the <em>Leader</em> (Aggregator <tt>0</tt>) and one for the <em>Helper</em> (Aggregator <tt>1</tt>).</t>
        <t>The sharding randomness is consumed as the VDPF's <tt>RAND_SIZE</tt> bytes (one
initial seed per Aggregator; <xref target="vdpf-params"/>), followed by four more seeds: the
Helper's proof-share seed, one joint-randomness blind per Aggregator, and one
prove-randomness seed. If <tt>flp.JOINT_RAND_LEN == 0</tt>, the two blinds are omitted,
leaving two more seeds. There is no measurement-share seed, because the FLP's
encoded measurement is exactly the VDPF block, which the VDPF already
secret-shares; the only secret a Client shares explicitly is the proof.</t>
        <sourcecode type="python"><![CDATA[
RAND_SIZE = (self.vdpf.RAND_SIZE
             + (1 + self.SHARES + 1) * self.xof.SEED_SIZE)
             # if flp.JOINT_RAND_LEN > 0

RAND_SIZE = (self.vdpf.RAND_SIZE
             + (1 + 1) * self.xof.SEED_SIZE)
             # if flp.JOINT_RAND_LEN == 0
]]></sourcecode>
      </section>
      <section anchor="verification">
        <name>Verification</name>
        <ol spacing="normal" type="1"><li>
            <t>Evaluate the VDPF share (<xref target="vdpf-key-eval"/>) over all <tt>num_leaf_nodes *
  leaf_size</tt> coordinates to obtain the Aggregator's share of the encoded vector,
  along with one sparsity proof per leaf.  Derive a one-hot check value by
  hashing the concatenation of those proofs, in leaf order, under the shared
  <tt>verify_key</tt>. The two Aggregators' proofs agree at every leaf exactly when at
  most one leaf is on-path, so verification rejects the report unless the two
  check values are equal.</t>
          </li>
          <li>
            <t>Sum the encoded vector share block-wise to obtain the Aggregator's share of
<tt>encoded_block</tt>, the FLP-encoded measurement produced by <tt>shard()</tt>.
Separately, apply <tt>flp.truncate()</tt> to each block of the encoded vector share;
the concatenation of the results is the Aggregator's output share.</t>
          </li>
          <li>
            <t>If <tt>flp.JOINT_RAND_LEN &gt; 0</tt>, recompute the Aggregator's own joint-randomness
part from its blind, the nonce, the encoded public share, and its VDPF seed,
exactly as <tt>shard()</tt> did. Combine it with the peer's part supplied in the
public share to derive the corrected joint-randomness seed, and expand that
into the joint randomness.  The corrected seed is cross-checked against the
verifier message in <tt>verify_next()</tt>, as in <xref section="7.2.2" sectionFormat="of" target="VDAF"/>. Otherwise, there is no joint randomness, and the Aggregator uses an
empty one in the next step.</t>
          </li>
          <li>
            <t>For each of the <tt>PROOFS</tt> proofs, query the Aggregator's share of
<tt>encoded_block</tt> and its share of that proof, obtaining a verifier share.</t>
          </li>
        </ol>
        <t>The Aggregators then exchange verifier shares, and
<tt>verifier_shares_to_message()</tt> rejects the report if the one-hot check values
differ or if <tt>flp.decide()</tt> fails on any combined verifier, and otherwise
outputs the joint-randomness seed derived from both Aggregators' parts as the
verifier message. If <tt>flp.JOINT_RAND_LEN == 0</tt>, there are no parts to combine,
and the verifier message is empty.</t>
        <sourcecode type="python"><![CDATA[
def verifier_shares_to_message(
        self,
        ctx: bytes,
        agg_param: None,
        verifier_shares: list[PreambleVerifierShare[F]],
        ) -> PreambleVerifierMessage:
    assert len(verifier_shares) == self.SHARES
    (share_0, share_1) = verifier_shares
    if share_0.one_hot_check != share_1.one_hot_check:
        raise ValueError("One-hot check failed")

    # Unshard the verifier shares into the verifier message.
    verifiers = vec_add(share_0.verifiers_share,
                        share_1.verifiers_share)

    # Verify that each proof is well-formed and the input is valid.
    for _ in range(self.PROOFS):
        (verifier, verifiers) = front(
            self.flp.VERIFIER_LEN, verifiers)
        if not self.flp.decide(verifier):
            raise ValueError(
                "Decision function failed after combining all "
                "verifier shares.")

    if self.flp.JOINT_RAND_LEN == 0:
        return None

    # Combine the joint randomness parts computed by the Aggregators
    # into the true joint randomness seed, which is checked by all
    # Aggregators.
    (part_0, part_1) = (verifier_shares[0].joint_rand_part,
                        verifier_shares[1].joint_rand_part)
    if part_0 is None or part_1 is None:
        raise ValueError("expected joint randomness parts")
    return self.joint_rand_seed(ctx, [part_0, part_1])
]]></sourcecode>
      </section>
      <section anchor="agg-param-validity">
        <name>Validity of Aggregation Parameters</name>
        <t>PREAMBLE does not use an aggregation parameter. Every input share MUST be used
only once:</t>
        <sourcecode type="python"><![CDATA[
def is_valid(self, agg_param, previous_agg_params):
    return len(previous_agg_params) == 0
]]></sourcecode>
      </section>
      <section anchor="aggregation">
        <name>Aggregation</name>
        <t>An output share is this Aggregator's share of every block's aggregatable form:
<tt>num_leaf_nodes</tt> consecutive groups of <tt>flp.OUTPUT_LEN</tt> field elements in all
(<xref target="vdaf"/>).</t>
        <t>Aggregating a set of output shares sums them element-wise:</t>
        <sourcecode type="python"><![CDATA[
def agg_init(self, agg_param: None) -> PreambleAggShare[F]:
    return self.field.zeros(self.output_len)

def agg_update(
        self,
        agg_param: None,
        agg_share: PreambleAggShare[F],
        out_share: PreambleOutputShare[F],
) -> PreambleAggShare[F]:
    return vec_add(agg_share, out_share)

def merge(
        self,
        agg_param: None,
        agg_shares: list[PreambleAggShare[F]],
) -> PreambleAggShare[F]:
    agg = self.agg_init(agg_param)
    for agg_share in agg_shares:
        agg = vec_add(agg, agg_share)
    return agg

def encode_agg_param(self, agg_param: None) -> bytes:
    return b""
]]></sourcecode>
      </section>
      <section anchor="unsharding">
        <name>Unsharding</name>
        <t>To unshard, the Collector adds up the aggregate shares element-wise, then
decodes each block's <tt>flp.OUTPUT_LEN</tt> field elements with the circuit that
validated it, using the <tt>blocks()</tt> helper (<xref target="aux"/>) to split the flat aggregate
into one slice per block. The result is one <tt>FLPResult</tt> per block, in block
order:</t>
        <sourcecode type="python"><![CDATA[
def unshard(self,
            agg_param: None,
            agg_shares: list[PreambleAggShare[F]],
            num_measurements: int) -> PreambleAggResult[FLPResult]:
    agg = self.merge(agg_param, agg_shares)
    # The aggregate is one truncated block after another, and each
    # block is decoded by the circuit that validated it -- so the
    # result is one FLP aggregate result per block, in leaf
    # order.
    return [
        self.flp.decode(block, num_measurements)
        for block in self.blocks(agg, self.flp.OUTPUT_LEN)
    ]
]]></sourcecode>
      </section>
      <section anchor="msg-serialization">
        <name>Message Serialization</name>
        <section anchor="msg-public-share">
          <name>Public Share</name>
          <t>The public share is the VDPF public share (<tt>CorrectionWords</tt>) output by key
generation (<xref target="vdpf-key-gen"/>), followed by the two Aggregators'
joint-randomness parts, which are absent if <tt>flp.JOINT_RAND_LEN == 0</tt>.  The
VDPF public share has <tt>depth</tt> internal correction words, a leaf correction word
of <tt>flp.MEAS_LEN</tt> field elements, and a leaf proof correction word. The control
bits are represented here as full bytes rather than bit-packed, matching this
document's reference implementation.</t>
          <artwork><![CDATA[
struct {
    uint8 seed_cw[KEY_SIZE];
    uint8 ctrl_bit_left;   /* MUST be 0 or 1 */
    uint8 ctrl_bit_right;  /* MUST be 0 or 1 */
} InternalCorrectionWord;

struct {
    InternalCorrectionWord internal_cws[depth];
    F leaf_cw[flp.MEAS_LEN];
    uint8 proof_cw[PROOF_SIZE];
} CorrectionWords;

struct {
    CorrectionWords cws;
    /* only if flp.JOINT_RAND_LEN > 0 */
    uint8 joint_rand_parts[2 * xof.SEED_SIZE];
} PreamblePublicShare;
]]></artwork>
          <t>The <tt>CorrectionWords</tt> are encoded and decoded as follows. <tt>leaf_size</tt> is
<tt>flp.MEAS_LEN</tt>, so <tt>correction_words_size()</tt> is the length of the encoded
<tt>CorrectionWords</tt>:</t>
          <sourcecode type="python"><![CDATA[
def encode_correction_words(self, cws: CorrectionWords[F]) -> bytes:
    result = bytes()
    for internal_cw in cws.internal_cws:
        result += internal_cw.seed_cw
        result += byte(internal_cw.ctrl_bit_left)
        result += byte(internal_cw.ctrl_bit_right)
    result += self.field.encode_vec(cws.leaf_cw)
    result += cws.proof_cw
    return result

def correction_words_size(self) -> int:
    return (self.depth * (self.KEY_SIZE + 2) +
            self.field.ENCODED_SIZE * self.leaf_size +
            PROOF_SIZE)

def decode_correction_words(
        self, encoded: bytes) -> CorrectionWords[F]:
    if len(encoded) != self.correction_words_size():
        raise ValueError("correction words have incorrect length")
    internal_cws = []
    for _ in range(self.depth):
        (seed_cw, encoded) = front(self.KEY_SIZE, encoded)
        (ctrl_bits, encoded) = front(2, encoded)
        if any(b > 1 for b in ctrl_bits):
            raise ValueError("invalid control bit")
        internal_cws.append(InternalCorrectionWord(
            seed_cw, bool(ctrl_bits[0]), bool(ctrl_bits[1])))
    (leaf_bytes, encoded) = front(
        self.field.ENCODED_SIZE * self.leaf_size, encoded)
    leaf_cw = self.field.decode_vec(leaf_bytes)
    return CorrectionWords(internal_cws, leaf_cw, encoded)
]]></sourcecode>
        </section>
        <section anchor="msg-input-share">
          <name>Input Share</name>
          <t>In both input shares, <tt>joint_rand_blind</tt> is absent if
<tt>flp.JOINT_RAND_LEN == 0</tt>.</t>
          <t>The Leader's input share:</t>
          <artwork><![CDATA[
struct {
    uint8 vdpf_seed[KEY_SIZE];
    F proof_share[flp.PROOF_LEN * PROOFS];
    /* only if flp.JOINT_RAND_LEN > 0 */
    uint8 joint_rand_blind[xof.SEED_SIZE];
} PreambleLeaderShare;
]]></artwork>
          <t>The Helper's input share replaces the Leader's explicit <tt>proof_share</tt> vector
with a single seed, which the Helper expands using <tt>helper_proof_share()</tt>:</t>
          <artwork><![CDATA[
struct {
    uint8 vdpf_seed[KEY_SIZE];
    uint8 proof_share[xof.SEED_SIZE];
    /* only if flp.JOINT_RAND_LEN > 0 */
    uint8 joint_rand_blind[xof.SEED_SIZE];
} PreambleHelperShare;
]]></artwork>
        </section>
        <section anchor="msg-verifier-share">
          <name>Verifier Share</name>
          <t><tt>joint_rand_part</tt> is absent if <tt>flp.JOINT_RAND_LEN == 0</tt>.</t>
          <artwork><![CDATA[
struct {
    uint8 one_hot_check[PROOF_SIZE];
    F verifiers_share[flp.VERIFIER_LEN * PROOFS];
    /* only if flp.JOINT_RAND_LEN > 0 */
    uint8 joint_rand_part[xof.SEED_SIZE];
} PreambleVerifierShare;
]]></artwork>
        </section>
        <section anchor="msg-verifier-message">
          <name>Verifier Message</name>
          <t>The verifier message is empty (zero bytes) if
<tt>flp.JOINT_RAND_LEN == 0</tt>.</t>
          <artwork><![CDATA[
/* only if flp.JOINT_RAND_LEN > 0 */
PreambleVerifierMessage = uint8[xof.SEED_SIZE]
]]></artwork>
        </section>
        <section anchor="msg-agg-share">
          <name>Aggregate Share and Output Share</name>
          <t>Both the aggregate share and the output share are a flat vector of
<tt>num_leaf_nodes * flp.OUTPUT_LEN</tt>-many field elements:</t>
          <artwork><![CDATA[
agg_share = out_share = F[num_leaf_nodes * flp.OUTPUT_LEN];
]]></artwork>
        </section>
      </section>
      <section anchor="aux">
        <name>Auxiliary</name>
        <sourcecode type="python"><![CDATA[
def blocks(self, vec: list[F], block_len: int) -> list[list[F]]:
    """
    Split a flat vector into one slice per block of the vector
    space, in leaf order.

    Both vectors Preamble handles have this shape: the encoded one
    that `vdpf.eval_all()` returns (`block_len == vdpf.leaf_size`)
    and the truncated one that is aggregated (`block_len ==
    flp.OUTPUT_LEN`).  Neither is typed as `list[list[F]]`, because a
    flat vector is what the wire encoding and `vec_add` want -- an
    output share is summed across Clients element-wise, and its block
    boundaries carry no information the shape doesn't already fix. So
    the boundaries live here instead, in one place, rather than as
    index arithmetic at each use.

    """
    expected = self.vdpf.num_leaf_nodes * block_len
    if len(vec) != expected:
        raise ValueError(
            f"expected {expected} field elements "
            f"({self.vdpf.num_leaf_nodes} blocks of {block_len}), "
            f"got {len(vec)}.")
    return [vec[i * block_len:(i + 1) * block_len]
            for i in range(self.vdpf.num_leaf_nodes)]
]]></sourcecode>
        <t>The joint randomness seed is derived from the Aggregators' parts as in Prio3
(<xref section="7.2.6" sectionFormat="of" target="VDAF"/>), except that the domain separation tag is built with
<tt>dst_alg()</tt> (<xref target="dst"/>):</t>
        <sourcecode type="python"><![CDATA[
def joint_rand_seed(self,
                    ctx: bytes,
                    joint_rand_parts: list[bytes]) -> bytes:
    """Derive the joint randomness seed from its parts."""
    return self.xof.derive_seed(
        zeros(self.xof.SEED_SIZE),
        dst_alg(USAGE_JOINT_RAND_SEED, self.ID, ctx),
        concat(joint_rand_parts),
    )
]]></sourcecode>
      </section>
      <section anchor="variants">
        <name>Variants</name>
        <t>This section defines four instantiations of PREAMBLE. Each fixes the validity
circuit wrapped by <tt>flp</tt> (<xref target="flp"/>) to one of the Prio3 circuits of <xref section="7.4" sectionFormat="of" target="VDAF"/> or, for PreambleL1BoundSum, to the circuit of <xref target="Prio3L1BoundSum"/>, and
the XOF to <tt>XofTurboShake128</tt> (<xref section="6.2.1" sectionFormat="of" target="VDAF"/>). In
PreambleMultihotCountVec, PreambleSumVec and PreambleL1BoundSum, <tt>block_size</tt> is
the circuit's <tt>length</tt> parameter: the number of entries in the block content a
Client submits, not the number of field elements that content encodes to. In
PreambleCount, <tt>block_size</tt> is fixed to 1. Each instantiation has its own
algorithm identifier, which feeds every domain separation tag (<xref target="dst"/>),
including the VDPF's.</t>
        <t>Like Prio3, each instantiation uses <tt>Field128</tt> and a single proof.</t>
        <section anchor="preamble-count">
          <name>PreambleCount</name>
          <table>
            <name>Parameters for PreambleCount</name>
            <thead>
              <tr>
                <th align="left">Parameter</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>ID</tt></td>
                <td align="left">
                  <tt>0xFFFFFFFC</tt></td>
              </tr>
              <tr>
                <td align="left">
                  <tt>field</tt></td>
                <td align="left">
                  <tt>Field128</tt> (<xref section="6.1.4" sectionFormat="of" target="VDAF"/>)</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>Valid</tt></td>
                <td align="left">
                  <tt>Count(field)</tt> (<xref section="7.4.1" sectionFormat="of" target="VDAF"/>)</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>PROOFS</tt></td>
                <td align="left">
                  <tt>1</tt></td>
              </tr>
              <tr>
                <td align="left">
                  <tt>xof</tt></td>
                <td align="left">
                  <tt>XofTurboShake128</tt></td>
              </tr>
            </tbody>
          </table>
          <t><tt>block_size</tt> is fixed to 1, so it is not a parameter of this instantiation and
<tt>dimension</tt> is the number of blocks. The block content is a single integer, 0 or
1, as in Prio3Count, rather than a vector. The circuit encodes it as one field
element, so <tt>flp.MEAS_LEN = 1</tt>, and its truncation is the identity, so
<tt>flp.OUTPUT_LEN = 1</tt>. The aggregate result is one <tt>int</tt> per block: the number of
Clients that submitted a 1 for that block.</t>
          <t>This is the only instantiation with <tt>flp.JOINT_RAND_LEN == 0</tt>, so it has no
joint randomness parts, and its verifier message is empty (<xref target="flp"/>).</t>
        </section>
        <section anchor="preamble-multihot-count-vec">
          <name>PreambleMultihotCountVec</name>
          <table>
            <name>Parameters for PreambleMultihotCountVec</name>
            <thead>
              <tr>
                <th align="left">Parameter</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>ID</tt></td>
                <td align="left">
                  <tt>0xFFFFFFFE</tt></td>
              </tr>
              <tr>
                <td align="left">
                  <tt>field</tt></td>
                <td align="left">
                  <tt>Field128</tt> (<xref section="6.1.4" sectionFormat="of" target="VDAF"/>)</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>Valid</tt></td>
                <td align="left">
                  <tt>MultihotCountVec(field, block_size, max_weight, chunk_length)</tt> (<xref section="7.4.5" sectionFormat="of" target="VDAF"/>)</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>PROOFS</tt></td>
                <td align="left">
                  <tt>1</tt></td>
              </tr>
              <tr>
                <td align="left">
                  <tt>xof</tt></td>
                <td align="left">
                  <tt>XofTurboShake128</tt></td>
              </tr>
            </tbody>
          </table>
          <t>The block content is a vector of <tt>block_size</tt> Boolean values of which at most
<tt>max_weight</tt> are <tt>True</tt>, as in Prio3MultihotCountVec, and <tt>0 &lt; max_weight &lt;=
block_size</tt>. The circuit encodes it as the <tt>block_size</tt> counters followed by
<tt>max_weight.bit_length()</tt> bits of reported weight, so <tt>flp.MEAS_LEN =
block_size + max_weight.bit_length()</tt>, and truncates the encoding to the
counters, so <tt>flp.OUTPUT_LEN = block_size</tt>. The aggregate result is one
<tt>list[int]</tt> of <tt>block_size</tt> counts per block.</t>
        </section>
        <section anchor="preamble-sum-vec">
          <name>PreambleSumVec</name>
          <table>
            <name>Parameters for PreambleSumVec</name>
            <thead>
              <tr>
                <th align="left">Parameter</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>ID</tt></td>
                <td align="left">
                  <tt>0xFFFFFFFD</tt></td>
              </tr>
              <tr>
                <td align="left">
                  <tt>field</tt></td>
                <td align="left">
                  <tt>Field128</tt> (<xref section="6.1.4" sectionFormat="of" target="VDAF"/>)</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>Valid</tt></td>
                <td align="left">
                  <tt>SumVec(field, block_size, 2^bits - 1, chunk_length)</tt> (<xref section="7.4.3" sectionFormat="of" target="VDAF"/>)</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>PROOFS</tt></td>
                <td align="left">
                  <tt>1</tt></td>
              </tr>
              <tr>
                <td align="left">
                  <tt>xof</tt></td>
                <td align="left">
                  <tt>XofTurboShake128</tt></td>
              </tr>
            </tbody>
          </table>
          <t>The block content is a vector of <tt>block_size</tt> integers, each in the range <tt>[0,
2^bits)</tt>, as in Prio3SumVec, so the circuit's <tt>max_measurement</tt> is <tt>2^bits - 1</tt>.
The circuit encodes each integer as <tt>bits</tt> field elements, so <tt>flp.MEAS_LEN =
block_size * bits</tt>, and truncates the encoding by recombining those bits, so
<tt>flp.OUTPUT_LEN = block_size</tt>. The aggregate result is one <tt>list[int]</tt> of
<tt>block_size</tt> sums per block. As in Prio3SumVec, it is RECOMMENDED to set
<tt>chunk_length</tt> to an integer near the square root of <tt>flp.MEAS_LEN</tt> (<xref section="7.4.3.1" sectionFormat="of" target="VDAF"/>).</t>
        </section>
        <section anchor="preamble-l1-bound-sum">
          <name>PreambleL1BoundSum</name>
          <table>
            <name>Parameters for PreambleL1BoundSum</name>
            <thead>
              <tr>
                <th align="left">Parameter</th>
                <th align="left">Value</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td align="left">
                  <tt>ID</tt></td>
                <td align="left">
                  <tt>0xFFFFFFFB</tt></td>
              </tr>
              <tr>
                <td align="left">
                  <tt>field</tt></td>
                <td align="left">
                  <tt>Field128</tt> (<xref section="6.1.4" sectionFormat="of" target="VDAF"/>)</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>Valid</tt></td>
                <td align="left">
                  <tt>L1BoundSum(field, block_size, max_value, chunk_length)</tt> (<xref target="Prio3L1BoundSum"/>)</td>
              </tr>
              <tr>
                <td align="left">
                  <tt>PROOFS</tt></td>
                <td align="left">
                  <tt>1</tt></td>
              </tr>
              <tr>
                <td align="left">
                  <tt>xof</tt></td>
                <td align="left">
                  <tt>XofTurboShake128</tt></td>
              </tr>
            </tbody>
          </table>
          <t>The block content is a vector of <tt>block_size</tt> integers, each in the range <tt>[0,
max_value]</tt>, whose sum is also at most <tt>max_value</tt>, as in Prio3L1BoundSum. The
bound is on the block's L1 norm, not on each coordinate independently, which
distinguishes this instantiation from PreambleSumVec. The circuit is defined in
<xref target="Prio3L1BoundSum"/> and is not repeated here. With <tt>bits =
max_value.bit_length()</tt>, it encodes each integer as <tt>bits</tt> field elements,
followed by <tt>bits</tt> field elements for the bit-decomposed claimed sum, which the
circuit checks against the coordinates. So <tt>flp.MEAS_LEN = (block_size + 1) *
bits</tt>.  The truncation drops the claimed sum, so <tt>flp.OUTPUT_LEN = block_size</tt>:
the VDPF carries the claimed sum, but it is not aggregated. The aggregate
result is one <tt>list[int]</tt> of <tt>block_size</tt> sums per block. As in PreambleSumVec,
it is RECOMMENDED to set <tt>chunk_length</tt> to an integer near the square root of
<tt>flp.MEAS_LEN</tt>.</t>
        </section>
      </section>
    </section>
    <section anchor="security-considerations">
      <name>Security Considerations</name>
      <ul empty="true">
        <li>
          <t>TODO</t>
        </li>
      </ul>
    </section>
    <section anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>IANA is requested to add new identifiers to the "VDAF Identifiers" registry,
under the "Verifiable Distributed Aggregation Functions (VDAF)" heading, which
is described in <xref section="10" sectionFormat="of" target="VDAF"/>. The new entries are as follows:</t>
      <table anchor="codepoints">
        <name>Additional entries for the VDAF Identifiers registry</name>
        <thead>
          <tr>
            <th align="left">Value</th>
            <th align="left">Scheme</th>
            <th align="left">Type</th>
            <th align="left">Reference</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td align="left">
              <tt>0xFFFFFFFE</tt></td>
            <td align="left">PreambleMultihotCountVec</td>
            <td align="left">VDAF</td>
            <td align="left">
              <xref target="variants"/> of RFC XXXX</td>
          </tr>
          <tr>
            <td align="left">
              <tt>0xFFFFFFFD</tt></td>
            <td align="left">PreambleSumVec</td>
            <td align="left">VDAF</td>
            <td align="left">
              <xref target="variants"/> of RFC XXXX</td>
          </tr>
          <tr>
            <td align="left">
              <tt>0xFFFFFFFC</tt></td>
            <td align="left">PreambleCount</td>
            <td align="left">VDAF</td>
            <td align="left">
              <xref target="variants"/> of RFC XXXX</td>
          </tr>
          <tr>
            <td align="left">
              <tt>0xFFFFFFFB</tt></td>
            <td align="left">PreambleL1BoundSum</td>
            <td align="left">VDAF</td>
            <td align="left">
              <xref target="variants"/> of RFC XXXX</td>
          </tr>
        </tbody>
      </table>
      <ul empty="true">
        <li>
          <t>TODO The codepoints in this section are from the private codepoint range and
are used for testing purposes. We will update this table with the codepoints
assigned by IANA.</t>
        </li>
      </ul>
      <t>(RFC EDITOR: Please replace "RFC XXXX" above with the RFC number assigned to
this document.)</t>
    </section>
  </middle>
  <back>
    <references anchor="sec-combined-references">
      <name>References</name>
      <references anchor="sec-normative-references">
        <name>Normative References</name>
        <reference anchor="Prio3L1BoundSum">
          <front>
            <title>A Prio Instantiation for Vector Sums with an L1 Norm Bound on Contributions</title>
            <author fullname="Martin Thomson" initials="M." surname="Thomson">
              <organization>Mozilla</organization>
            </author>
            <author fullname="David Cook" initials="D." surname="Cook">
              <organization>ISRG</organization>
            </author>
            <date day="29" month="April" year="2026"/>
            <abstract>
              <t>   A Prio Verifiable Distributed Aggregation Function is defined that
   supports vector or histogram addition, where the sum of the values in
   the contribution is less than a chosen value.

              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-ietf-ppm-l1-bound-sum-02"/>
        </reference>
        <reference anchor="VDAF">
          <front>
            <title>Verifiable Distributed Aggregation Functions</title>
            <author fullname="Richard Barnes" initials="R." surname="Barnes">
              <organization>Cisco</organization>
            </author>
            <author fullname="David Cook" initials="D." surname="Cook">
              <organization>ISRG</organization>
            </author>
            <author fullname="Christopher Patton" initials="C." surname="Patton">
              <organization>Cloudflare</organization>
            </author>
            <author fullname="Phillipp Schoppmann" initials="P." surname="Schoppmann">
              <organization>Google</organization>
            </author>
            <date day="30" month="January" year="2026"/>
            <abstract>
              <t>   This document describes Verifiable Distributed Aggregation Functions
   (VDAFs), a family of multi-party protocols for computing aggregate
   statistics over user measurements.  These protocols are designed to
   ensure that, as long as at least one aggregation server executes the
   protocol honestly, individual measurements are never seen by any
   server in the clear.  At the same time, VDAFs allow the servers to
   detect if a malicious or misconfigured client submitted an invalid
   measurement.  Two concrete VDAFs are specified, one for general-
   purpose aggregation (Prio3) and another for heavy hitters (Poplar1).

              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-irtf-cfrg-vdaf-18"/>
        </reference>
        <reference anchor="RFC2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author fullname="S. Bradner" initials="S." surname="Bradner"/>
            <date month="March" year="1997"/>
            <abstract>
              <t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
          <seriesInfo name="DOI" value="10.17487/RFC2119"/>
        </reference>
        <reference anchor="RFC8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author fullname="B. Leiba" initials="B." surname="Leiba"/>
            <date month="May" year="2017"/>
            <abstract>
              <t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t>
            </abstract>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
          <seriesInfo name="DOI" value="10.17487/RFC8174"/>
        </reference>
      </references>
      <references anchor="sec-informative-references">
        <name>Informative References</name>
        <reference anchor="Mastic">
          <front>
            <title>The Mastic VDAF</title>
            <author fullname="Hannah Davis" initials="H." surname="Davis">
              <organization>Seagate</organization>
            </author>
            <author fullname="Dimitris Mouris" initials="D." surname="Mouris">
              <organization>Nillion</organization>
            </author>
            <author fullname="Christopher Patton" initials="C." surname="Patton">
              <organization>Cloudflare</organization>
            </author>
            <author fullname="Nektarios Georgios Tsoutsos" initials="N. G." surname="Tsoutsos">
              <organization>University of Delaware</organization>
            </author>
            <date day="23" month="January" year="2025"/>
            <abstract>
              <t>   This document describes Mastic, a two-party VDAF for the following
   secure aggregation task: each client holds an input string and an
   associated weight, and the data collector wants to aggregate the
   weights of all clients whose inputs begin with a prefix chosen by the
   data collector.  This functionality enables two classes of
   applications.  First, it allows grouping metrics by client attributes
   without revealing which clients have which attributes.  Second, it
   solves the weighted heavy hitters problem, where the goal is to
   compute the subset of inputs that have the highest total weight.

              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-mouris-cfrg-mastic-04"/>
        </reference>
        <reference anchor="PINE">
          <front>
            <title>Private Inexpensive Norm Enforcement (PINE) VDAF</title>
            <author fullname="Junye Chen" initials="J." surname="Chen">
              <organization>Apple Inc.</organization>
            </author>
            <author fullname="Christopher Patton" initials="C." surname="Patton">
              <organization>Cloudflare</organization>
            </author>
            <date day="4" month="February" year="2025"/>
            <abstract>
              <t>   This document describes PINE, a Verifiable Distributed Aggregation
   Function (VDAF) for secure aggregation of high-dimensional, real-
   valued vectors with bounded L2-norm.  PINE is intended to facilitate
   private and robust federated machine learning.

              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-chen-cfrg-vdaf-pine-02"/>
        </reference>
        <reference anchor="BBCGGI19" target="https://ia.cr/2019/188">
          <front>
            <title>Zero-Knowledge Proofs on Secret-Shared Data via Fully Linear PCPs</title>
            <author initials="D." surname="Boneh">
              <organization/>
            </author>
            <author initials="E." surname="Boyle">
              <organization/>
            </author>
            <author initials="H." surname="Corrigan-Gibbs">
              <organization/>
            </author>
            <author initials="N." surname="Gilboa">
              <organization/>
            </author>
            <author initials="Y." surname="Ishai">
              <organization/>
            </author>
            <date year="2019"/>
          </front>
          <seriesInfo name="CRYPTO 2019" value=""/>
        </reference>
        <reference anchor="DP22" target="https://doi.org/10.1007/978-3-031-06944-4_6">
          <front>
            <title>Lightweight, Maliciously Secure Verifiable Function Secret Sharing</title>
            <author initials="L." surname="deCastro">
              <organization/>
            </author>
            <author initials="A." surname="Polychroniadou">
              <organization/>
            </author>
            <date year="2022"/>
          </front>
          <seriesInfo name="EUROCRYPT 2022" value=""/>
        </reference>
        <reference anchor="PREAMBLE" target="https://arxiv.org/abs/2503.11897">
          <front>
            <title>PREAMBLE: Private and Efficient Aggregation via Block Sparse Vectors</title>
            <author initials="H." surname="Asi">
              <organization/>
            </author>
            <author initials="V." surname="Feldman">
              <organization/>
            </author>
            <author initials="H." surname="Keller">
              <organization/>
            </author>
            <author initials="G." surname="Rothblum">
              <organization/>
            </author>
            <author initials="K." surname="Talwar">
              <organization/>
            </author>
            <date year="2025"/>
          </front>
        </reference>
      </references>
    </references>
    <?line 1239?>

<section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
    </section>
    <section numbered="false" anchor="test-vectors">
      <name>Test Vectors</name>
    </section>
  </back>
  <!-- ##markdown-source:
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
4KNTI0xD5RxdMtXqqX5YNdW7neNTd6qERrqF7TQmxC8eAMDn/eEWXgW5ny+I
/qy6iS1I0Pz5jD7ftqmGQ3dX+385Bc07wHMyd5FeDcJcP8c7T4DroAthcdEH
lQqdkfdPte1OtXv0FtjdadtcaEy7f561Uz11pzp6u//L0en57i/7u3+G+YBy
X2mUoPnIGYai/4Lj0Yx38v6pUBA27NIVfx1uiaLvI8s4joS2g+BryDwa78SH
MiGXmGktASNkUCLpF91DKjZGSpbI4BPiHefoLonZyk5mZ9tQvVTbf2MHyqZy
GnOwD3rRY/72p5fAL8RHn6Prpj/LPsJWsnKyzGrtXAI+g4fBtm30XFXWLUYc
lT1gA/ULWhd56Bitd+Q6TvNLdscmCkBe9+uiTxZUEASvtERhTLwySVKW2hDu
OSPxbpDfQZ8pjiguY+PNgTMHAeRvsgzthxQnRURzC5oRy90RM04zNsODfV82
wpP0tHMlIueKDV5yz8Yx/1ZkdO1ZDyiul+dFu1V2SY0iLSXgYhPjb2SJNvqO
2dbX/wOXRG0RXut/Xnl/rf7nX5gTupOtleUcOpMVoHmh4leILgQT3LlsG4dg
vy7uHm+f68/uTzMMrZobi44fvO0cJd5Jc8eI11XolkfKml9W4g4LPc0A8+GA
gwuBWow8N3boD0bNimI/eHQTOwDrh+Z9b12E6YAFGgGNmwatuaHzm4ZwFuVc
NjSBBjFCA1oyR0WC+pdNaeFNH7UHZN6M7+aHSVedVU9xhN2tFhzIt+36s2m+
q6ICMJBAjKMF9ISd0XD1PLcyi+4VxruVjo9Z+xLwgHo42DuJadtFOtAzf74R
Lxd9/D6d2G9OlnP6Gx23Tn8bbS3KtjlWLcKT0kpSNn+C5gUkle4xTR39U5SA
QeRGqtZo7QdATVJ0kCSoCSwA0qhf0P2wB2i8L9VyjmbkSVlUVWRszCZezbqX
NAXe1P5otI1tIpWfsy+NFn/06+m7X09RPYgjtq6Jq0ncldSoLpdo/6U9zpMF
+goMHBgwddHV/sjImLdprSEiPtZ+MGw+TVlPs8RADBEmTEXcKx10BWEEQGx5
V7D8rlCJkp1oiMY8/FT7aJDCC0YDaxF/dQniFPlCTjj8wRqdcOFHcEXp0vRP
nCt694juJ2o+70ywhS8k7JG/YWFsng/++azek3Xm/oZfYYR88M+Du5KZ8M/7
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
1CnsUr3n6JfWNv8fGyB5qAvVAAA=

-->

</rfc>
