<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<!-- name="GENERATOR" content="github.com/mmarkdown/mmark Mmark Markdown Processor - mmark.miek.nl" -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" version="3" ipr="trust200902" docName="draft-irtf-cfrg-bbs-signatures-11" submissionType="IETF" category="info" xml:lang="en" indexInclude="true">

<front>
<title abbrev="The BBS Signature Scheme">The BBS Signature Scheme</title><seriesInfo value="draft-irtf-cfrg-bbs-signatures-11" status="informational" name="Internet-Draft"/>
<author initials="T." surname="Looker" fullname="Tobias Looker"><organization>MATTR</organization><address><postal><street/>
</postal><email>tobias.looker@mattr.global</email>
</address></author><author initials="V." surname="Kalos" fullname="Vasilis Kalos"><organization>MATTR</organization><address><postal><street/>
</postal><email>vasilis.kalos@mattr.global</email>
</address></author><author initials="A." surname="Whitehead" fullname="Andrew Whitehead"><organization>Portage</organization><address><postal><street/>
</postal><email>andrew.whitehead@portagecybertech.com</email>
</address></author><author initials="M." surname="Lodder" fullname="Mike Lodder"><organization>CryptID</organization><address><postal><street/>
</postal><email>redmike7@gmail.com</email>
</address></author><date/>
<area>Internet</area>
<workgroup>CFRG</workgroup>

<abstract>
<t>This document describes the BBS Signature scheme, a secure, multi-message digital signature protocol, supporting proving knowledge of a signature while selectively disclosing any subset of the signed messages. Concretely, the scheme allows for signing multiple messages whilst producing a single, constant size, digital signature. Additionally, the possessor of a BBS signatures is able to create zero-knowledge, proofs of knowledge of a signature, while selectively disclosing subsets of the signed messages. Being zero-knowledge, the BBS proofs do not reveal any information about the undisclosed messages or the signature itself, while at the same time, guaranteeing the authenticity and integrity of the disclosed messages.</t>
</abstract>

<note title="Discussion Venues" removeInRFC="true">
<t>Source for this draft and an issue tracker can be found at
    <eref target="https://github.com/decentralized-identity/bbs-signature"/>.</t>
</note>
</front>

<middle>

<section anchor="introduction"><name>Introduction</name>
<t>A digital signature scheme is a fundamental cryptographic primitive that is used to provide data integrity and verifiable authenticity in various protocols. The core premise of digital signature technology is built upon asymmetric cryptography where-by the possessor of a private key is able to sign a message, where anyone in possession of the corresponding public key matching that of the private key is able to verify the signature.</t>
<t>Beyond the core properties of a digital signature scheme, the BBS signatures and proofs provide multiple additional unique properties. Three key ones are:</t>
<t><strong>Selective Disclosure</strong> - The scheme allows a Signer to sign multiple messages and produce a single -constant size- output signature. A Prover then possessing the messages and the signature can generate a proof whereby they can choose which messages to disclose, while revealing no information about the undisclosed messages. The proof itself guarantees the integrity and authenticity of the disclosed messages (e.g. that they were originally signed by the Signer).</t>
<t><strong>Unlinkable Proofs</strong> - The proofs generated by the scheme are zero-knowledge, proofs of knowledge of the signature, meaning a verifying party in receipt of a proof is unable to determine which signature was used to generate the proof, removing a common source of correlation. In general, the value of a BBS proof is indistinguishable from random even if generated from the same signature.</t>
<t><strong>Proof of Possession</strong> - The proofs generated by the scheme prove to a Verifier that the party who generated the proof (Prover) was in possession of a signature without revealing it. The scheme also supports binding a <tt>presentation_header</tt> to the generated proof, which acts as a message signed by the Prover. The <tt>presentation_header</tt> can include arbitrary information such as a cryptographic nonce, an audience/domain identifier and or time based validity information (for more details on the <tt>presentation_header</tt>, see <xref target="header-and-presentation-header-usage"/>).</t>
<t>Refer to the <xref target="use-cases"/> for an elaboration on situations where these properties are useful.</t>
<t>Below is a basic diagram describing the main entities involved in the scheme</t>
<figure><name>Basic diagram capturing the main entities involved in using the scheme
</name>
<sourcecode type="ascii-art"><![CDATA[  (1) sign                                      (3) ProofGen
   +-----                                         +-----
   |    |                                         |    |
   |    |                                         |    |
   |   \ /                                        |   \ /
+----------+                                   +-----------+
|          |                                   |           |
|          |                                   |           |
|          |                                   |           |
|  Signer  |---(2)* Send signature + msgs----->|  Holder/  |
|          |                                   |  Prover   |
|          |                                   |           |
|          |                                   |           |
+----------+                                   +-----------+
                                                     |
                                                     |
                                                     |
                                    (4)* Send proof + disclosed msgs
                                                     |
                                                     |
                                                    \ /
                                               +-----------+
                                               |           |
                                               |           |
                                               |           |
                                               | Verifier  |
                                               |           |
                                               |           |
                                               |           |
                                               +-----------+
                                                  |   / \
                                                  |    |
                                                  |    |
                                                  +-----
                                             (5) ProofVerify


]]>
</sourcecode>
</figure>
<t><strong>Note</strong> The protocols implied by the items annotated by an asterisk are out of scope for this specification</t>
<t>The name BBS is derived from the authors of the original academic work by Dan Boneh, Xavier Boyen, and Hovav Shacham <xref target="BBS04"/>, where the scheme was first described as part of a group signatures protocol. Soon after, the scheme was described by Camenisch and Lysyanskaya as a stand-alone signatures scheme in <xref target="CL04"/>, for anonymous credentials applications. Later, Au, Susilo an Mu presented the first, provably secure version of BBS Signatures in <xref target="ASM06"/>. Following, works by Camenisch, Drijvers and Lehmann <xref target="CDL16"/> and by Barki, Brunet, Desmoulins and Traore <xref target="BBDT16"/>, proved the security of the scheme in settings where more efficient computations are possible, thereby improving performance. Finally, in 2023, Tessaro and Zhu, presented in <xref target="TZ23"/> further performance improvements, shrinking the BBS signature. This document is mainly based on that work. More specifically, the BBS signature generation and verification algorithms are as defined in Section 3.1 of <xref target="TZ23"/> while the BBS proof generation and verification algorithms are as defined in Appendix B of the same work.</t>
<t>Note that the BBS Signatures scheme is based on the discrete logarithm problem. This means that it is not "post-quantum secure". However, the privacy and hiding properties of BBS proofs are resilient even against an attacker utilizing a Cryptographically Relevant Quantum Computer (<xref target="I-D.ietf-pquip-pqc-engineers"/>). See <xref target="post-quantum-security"/> for an elaboration on the security properties of BBS Signatures against such a computer.</t>

<section anchor="terminology"><name>Terminology</name>
<t>The following terminology is used throughout this document:</t>

<dl spacing="compact">
<dt>SK</dt>
<dd>The secret key for the signature scheme.</dd>
<dt>PK</dt>
<dd>The public key for the signature scheme.</dd>
<dt>message</dt>
<dd>An octet string, representing a signed message.</dd>
<dt>L</dt>
<dd>The total number of signed messages.</dd>
<dt>R</dt>
<dd>The number of message indexes that are disclosed (revealed) in a proof-of-knowledge of a signature.</dd>
<dt>U</dt>
<dd>The number of message indexes that are undisclosed in a proof-of-knowledge of a signature.</dd>
<dt>scalar</dt>
<dd>An integer between 0 and r-1, where r is the prime order of the selected groups, defined by each ciphersuite (see also <xref target="notation"/>).</dd>
<dt>generator</dt>
<dd>A valid point on the selected subgroup of the curve being used that is employed to commit a value.</dd>
<dt>signature</dt>
<dd>The digital signature output.</dd>
<dt>header</dt>
<dd>A payload chosen by the Signer and bound to a BBS signature, as well as the BBS proofs generated using that signature.</dd>
<dt>presentation_header (ph)</dt>
<dd>A payload generated and bound to a specific BBS proof.</dd>
<dt>dst</dt>
<dd>The domain separation tag.</dd>
<dt>I2OSP</dt>
<dd>An operation that transforms a non-negative integer into an octet string, defined in Section 4 of <xref target="RFC8017"/>. The output of this operation is in big-endian order.</dd>
<dt>OS2IP</dt>
<dd>An operation that transforms a octet string into an non-negative integer, defined in Section 4 of <xref target="RFC8017"/>. The input of this operation must be in big-endian order.</dd>
<dt>INVALID, ABORT</dt>
<dd>Error indicators. INVALID refers to an error encountered during the Deserialization or Procedure steps of an operation. An INVALID value can be returned by a subroutine and handled by the calling operation. ABORT indicates that one or more of the initial constraints defined by the operation are not met. In that case, the operation will stop execution. An operation calling a subroutine that aborted must also immediately abort.</dd>
</dl>
</section>

<section anchor="notation"><name>Notation</name>
<t>The following notation and primitives are used:</t>

<dl spacing="compact">
<dt>a || b</dt>
<dd>Denotes the concatenation of octet strings a and b.</dd>
<dt>I \ J</dt>
<dd>Denotes the difference of the two sets I and J, i.e., all the elements of I that do not appear in J, in the same order as they were in I.</dd>
<dt>X[a..b]</dt>
<dd>Denotes a slice of the array <tt>X</tt> containing all elements from and including the value at index <tt>a</tt> until and including the value at index <tt>b</tt>. Note when this syntax is applied to an octet string, each element in the array <tt>X</tt> is assumed to be a single byte.</dd>
<dt>length(input)</dt>
<dd>Takes as input either an array or an octet string. If the input is an array, returns the number of elements of the array. If the input is an octet string, returns the number of bytes of the inputted octet string.</dd>
<dt>X[i]</dt>
<dd>Denotes the element of array <tt>X</tt> at index <tt>i</tt>. Note that arrays in this document are considered "zero-indexed", meaning that element indexing starts from 0 rather than 1. For example, if <tt>X = [a, b, c, d]</tt> then <tt>X[0] = a</tt>, <tt>X[1] = b</tt>, <tt>X[2] = c</tt> and <tt>X[3] = d</tt>.</dd>
</dl>
<t>Terms specific to pairing-friendly elliptic curves that are relevant to this document are restated below, originally defined in <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/>.</t>

<dl spacing="compact">
<dt>E1, E2</dt>
<dd>elliptic curve groups defined over finite fields. This document assumes that E1 has a more compact representation than E2, i.e., because E1 is defined over a smaller field than E2. For a pairing-friendly curve, this document denotes operations in E1 and E2 in additive notation, i.e., P + Q denotes point addition and P * x denotes scalar multiplication, where x is a scalar.</dd>
<dt>G1, G2</dt>
<dd>subgroups of E1 and E2 (respectively) having prime order r.</dd>
<dt>GT</dt>
<dd>a subgroup, of prime order r, of the multiplicative group of a field extension.</dd>
<dt>h</dt>
<dd>G1 x G2 -&gt; GT: a non-degenerate bilinear map.</dd>
<dt>r</dt>
<dd>The prime order of the G1 and G2 subgroups.</dd>
<dt>BP1, BP2</dt>
<dd>base (constant) points on the G1 and G2 subgroups respectively.</dd>
<dt>Identity_G1, Identity_G2, Identity_GT</dt>
<dd>The identity element for the G1, G2, and GT subgroups respectively.</dd>
<dt>hash_to_curve_g1(ostr, dst) -&gt; P</dt>
<dd>A cryptographic hash function that takes an arbitrary octet string as input and returns a point in G1, using the hash_to_curve operation defined in <xref target="RFC9380"/> and the inputted dst as the domain separation tag for that operation (more specifically, the inputted dst will become the DST parameter for the hash_to_field operation, called by hash_to_curve).</dd>
<dt>expand_message(msg, dst, len) -&gt; ostr</dt>
<dd>returns a uniformly random octet string of <tt>len</tt> octets, deterministically on input a message <tt>msg</tt> to be hashed as an octet string, another octet string representing a domain separation tag <tt>dst</tt> and the number of octets to be returned (<tt>len</tt>).</dd>
<dt>point_to_octets_E1(P) -&gt; ostr, point_to_octets_E2(P) -&gt; ostr</dt>
<dd>returns the canonical representation of the point P of the elliptic curve E1 or E2 as an octet string. This operation is also known as serialization. Note that we assume that when the point is valid, all the serialization operations will always succeed to return the octet string representation of the point.</dd>
<dt>octets_to_point_E1(ostr) -&gt; P, octets_to_point_E2(ostr) -&gt; P</dt>
<dd>returns the point P for the respective elliptic curve corresponding to the canonical representation ostr, or INVALID if ostr is not a valid output of the respective point_to_octets_E* function. This operation is also known as deserialization.</dd>
<dt>subgroup_check_G1(P), subgroup_check_G2(P) -&gt; VALID or INVALID</dt>
<dd>returns VALID when the point P is an element of the subgroup G1 or G2 correspondingly, and INVALID otherwise. This function can always be implemented by checking that r * P is equal to the identity element. In some cases, faster checks may also exist, e.g., <xref target="Bowe19"/>. Note that these functions should always return VALID, on input the Identity point of the corresponding subgroup.</dd>
</dl>
</section>

<section anchor="document-organization"><name>Document Organization</name>
<t>This document is organized as follows:</t>

<ul>
<li><t>Scheme Definition (<xref target="scheme-definition"/>), defines the core operations and parameters for the BBS signature scheme.</t>
</li>
<li><t>Utility Operations (<xref target="utility-operations"/>), defines utilities used by the BBS signature scheme.</t>
</li>
<li><t>Security Considerations (<xref target="security-considerations"/>), describes a set of security considerations associated to the signature scheme.</t>
</li>
<li><t>Ciphersuites (<xref target="ciphersuites"/>), defines the format of a ciphersuite, alongside a concrete ciphersuite based on the BLS12-381 curve.</t>
</li>
</ul>
</section>
</section>

<section anchor="conventions"><name>Conventions</name>
<t>The keywords <bcp14>MUST</bcp14>, <bcp14>MUST NOT</bcp14>, <bcp14>REQUIRED</bcp14>, <bcp14>SHALL</bcp14>, <bcp14>SHALL NOT</bcp14>, <bcp14>SHOULD</bcp14>,
<bcp14>SHOULD NOT</bcp14>, <bcp14>RECOMMENDED</bcp14>, <bcp14>MAY</bcp14>, and <bcp14>OPTIONAL</bcp14>, when they appear in this
document, are to be interpreted as described in <xref target="RFC2119"/>.</t>
</section>

<section anchor="scheme-definition"><name>Scheme Definition</name>
<t>This section defines the BBS signature scheme, including the parameters required to define a concrete instantiation of the protocol.</t>

<section anchor="parameters"><name>Parameters</name>
<t>The schemes operations defined in this section depend on the following parameters:</t>

<ul>
<li><t>A pairing-friendly elliptic curve, plus associated functionality given in <xref target="notation"/>.</t>
</li>
<li><t>A hash-to-curve suite as defined in <xref target="RFC9380"/>, using the aforementioned pairing-friendly curve. This defines the hash_to_curve and expand_message operations, used by this document.</t>
</li>
<li><t>get_random(n): returns a random octet string with a length of n bytes, sampled uniformly at random using a cryptographically secure pseudo-random number generator (CSPRNG) or a pseudo random function. See <xref target="RFC4086"/> for recommendations and requirements on the generation of random numbers.</t>
</li>
</ul>
</section>

<section anchor="interfaces"><name>Interfaces</name>
<t>The BBS signature scheme is organized as follows:</t>

<ul spacing="compact">
<li>A set of low level (core) operations, taking care of the main cryptographic functionality.</li>
<li>An Application Interface, that uses the core operations in a secure way.</li>
</ul>
<t>Together with a set of utility procedures, defining functionality that is common between different interface procedures or core operations, a full BBS Signatures deployment can be defined.</t>
<t>Each of the core operations (see <xref target="core-operations"/>) expects a list of points (called the generators, see <xref target="generators"/>) and a list of messages represented as scalar values (see <xref target="messages"/>). It is the job of the Interface to:</t>

<ol spacing="compact">
<li>Create the necessary generators.</li>
<li>Map the inputted messages to scalars.</li>
</ol>
<t>This allows for extensibility of the core scheme without exposing the resulting complexity to all applications. To ensure proper separation between BBS Interfaces with distinct functionality, each Interface is parametrized by a unique identifier (called <tt>api_id</tt>) that will be used as a domain separation tag (<tt>dst</tt>) by the core (<xref target="core-operations"/>) and utility (<xref target="interface-utilities"/>) procedures. A document extending the core functionality of BBS Signatures by defining a new Interface, MUST ensure that it adheres to the requirements described in <xref target="defining-new-interfaces"/>.</t>
</section>

<section anchor="considerations"><name>Considerations</name>

<section anchor="subgroup-selection"><name>Subgroup Selection</name>
<t>For defining BBS signatures there are two possible variations regarding the subgroup selection, namely where public keys are defined in G2 and signatures in G1 OR the opposite where public keys are defined in G1 and signatures in G2. Some pairing-based digital signature schemes such as <xref target="I-D.irtf-cfrg-bls-signature"/> elect to allow for both variations, because they optimize for different use cases. However, in case of BBS Signatures, due to the operations involved in both signature and proof generation being computationally inefficient when performed in G2 and in the pursuit of simplicity, the BBS Signatures scheme as defined in this document is limited to a construction where public keys are in G2 and signatures in G1.</t>
</section>

<section anchor="generators"><name>Generators</name>
<t>Throughout the operations of this signature scheme, each message that is signed is paired with a specific point of G1, called a generator. Specifically, if a generator <tt>H_1</tt> is multiplied with <tt>msg_1</tt> during signing, then <tt>H_1</tt> MUST be multiplied with <tt>msg_1</tt> in all other operations (signature verification, proof generation and proof verification). As a result, the messages must be passed to the operations of the BBS scheme in the same order.</t>
<t>Aside from the message generators, the scheme uses one additional generator <tt>Q_1</tt> to sign the signature's domain, which binds both the signature and generated proofs to a specific context and cryptographically protects any potential application-specific information (for example, messages that must always be disclosed, ciphersuite parameters or an application identifier). This document uses the procedures defined in <xref target="RFC9380"/> to create the generators. See <xref target="generators-calculation"/> on more details.</t>
</section>

<section anchor="messages"><name>Messages</name>
<t>In this document, the messages to be signed are defined as octet strings. Each message must be mapped to a scalar value before passed to one of the core BBS operations (<xref target="core-operations"/>). There are various ways to map a message to a scalar value. The BBS Signatures Interface defined in this document (see <xref target="bbs-signatures-interface"/>), makes use of a hash function (see <xref target="messages-to-scalars"/>). See <xref target="messages-to-scalars"/> on further details on how the each message is mapped to a scalar value and <xref target="mapping-messages-to-scalars"/> for more details and guidance on using alternative mapping methods.</t>
</section>

<section anchor="indexing-of-arrays"><name>Indexing of Arrays</name>
<t>Note that arrays in this document use the zero-based numbering common in many programming languages, meaning that element indexing starts from 0 (see <xref target="notation"/>). This is distinct from naming used during deserialization of arrays, where natural (one-based) numbering might be used as part of the names of the array's elements for clarity in that context.</t>
<t>For example, if <tt>X</tt> is an array of <tt>n</tt> elements, we may write,</t>

<artwork><![CDATA[[a_1, a_2, ..., a_n] = X
]]>
</artwork>
<t>The above would indicate that</t>

<artwork><![CDATA[X[0] = a_1
X[1] = a_2
// ... and so on, up to
X[n-1] = a_n
]]>
</artwork>
</section>

<section anchor="serializing-to-octets"><name>Serializing to Octets</name>
<t>When serializing one or more values to produce an octet string, each element will be encoded using a specific operation determined by its type. More concretely,</t>

<ul spacing="compact">
<li>Points in <tt>E*</tt> will be serialized using the <tt>point_to_octets_E*</tt> implementation for a particular ciphersuite.</li>
<li>Non-negative integers will be serialized using <tt>I2OSP</tt> with an output length of 8 bytes.</li>
<li>Scalars will be serialized using <tt>I2OSP</tt> with a constant output length defined by a particular ciphersuite.</li>
</ul>
<t>We also use strings in double quotes to represent ASCII-encoded literals. For example "BBS" will be used to refer to the octet string, <tt>010000100100001001010011</tt>.</t>
<t>Those rules will be used explicitly on every operation. See also <tt>serialize</tt> defined in <xref target="serialize"/>.</t>
</section>

<section anchor="header-and-presentation-header-usage"><name>Header and Presentation Header Usage</name>
<t>There are two special values defined by the BBS Scheme; the <tt>header</tt> and the <tt>presentation_header</tt>. The <tt>header</tt> value is chosen by the Signer and is bound to both a BBS signature and to any BBS proofs generated using that signature. Specifically, the Prover is required to reveal the <tt>header</tt> to the proof Verifier during every BBS proof presentation. As a result, the Signer SHOULD NOT include in the <tt>header</tt> any identifying information that may have the potential of compromising the Prover's privacy (see <xref target="privacy-considerations"/>). Suitable use cases taking advantage of the <tt>header</tt> value include binding a BBS signature (and subsequent BBS proofs) to a specific application, deployment or domain, (in general, binding the signature to specific sets of metadata).</t>
<t>Similarly, the Prover can choose a <tt>presentation_header</tt> value to be bound to the BBS proof (in contrast to the <tt>header</tt> value that is chosen by the Signer and is bound to both BBS proof and signature). Verifying a BBS proof will guarantee the authenticity and integrity of the <tt>presentation_header</tt> value. This makes it suitable for ensuring the freshness of a BBS proof, for example, by including in it a (possibly supplied by the Verifier) random value. Other use cases include binding the BBS proof to a certain domain/audience or validity period. The <tt>presentation_header</tt> can also be used by the Prover to sign a message. In this case, the Prover will add to the <tt>presentation_header</tt> the message they want to sign. A valid BBS proof guarantees that the message contained in the <tt>presentation_header</tt> was signed by the same Prover that generated that proof (similar to how group signatures work <xref target="BBS04"/>, where the group in this case will be all the Provers having received valid signatures under a specific public key).</t>
</section>

<section anchor="unlinkability"><name>Unlinkability</name>
<t>As mentioned in the Introduction, a BBS proof is unlinkable. In this section we will define the term in more detail. Formally, we use unlinkability to refer to the fact that a BBS proof is zero-knowledge <xref target="TZ23"/>. In practice, this guarantees that an adversary (a Verifier, the Issuer or coalitions between one or more Verifiers and the Issuer) will not be able to infer any information from the BBS proof value, other than what the Prover decided to provide, even with access to multiple proof values. Consequently, the Verifier will not be able to correlate multiple proofs generated by the same signature or Prover. Note however, that this holds only for the value of the BBS proof. In other words, other values revealed by the Prover during their interaction with a Verifier, may still be used to correlate their activity and compromise their privacy. Examples of such values include the disclosed messages (if the same message of high enough entropy is revealed between multiple proofs), the <tt>header</tt> and <tt>presentation_header</tt> values (see Section <xref target="header-and-presentation-header-usage"/>), or the total number of signed messages. See Section <xref target="privacy-considerations"/> for privacy considerations and recommendations on minimizing these sources of correlation.</t>
</section>
</section>

<section anchor="key-generation-operations"><name>Key Generation Operations</name>

<section anchor="secret-key"><name>Secret Key</name>
<t>This operation generates a secret key (SK) deterministically from a secret octet string (key_material). This operation is the RECOMMENDED way of generating a secret key, but its use is not required for compatibility, and implementations MAY use a different key generation procedure. For security, such an alternative MUST output a secret key that is statistically close to uniformly random in the range from 1 to r - 1. An example of an HKDF-based alternative is the KeyGen operation defined in Section 2.3 of <xref target="I-D.irtf-cfrg-bls-signature"/> (with an appropriate, BBS specific, salt value, like "BBS_SIG_KEYGEN_SALT_").</t>
<t>For security, key_material MUST be random and infeasible to guess, e.g. generated by a trusted source of randomness and with enough entropy. See <xref target="RFC4086"/> for suggestions on generating randomness. key_material MUST be at least 32 bytes long, but it MAY be longer.</t>
<t>KeyGen takes an optional input, key_info. This parameter MAY be used to derive distinct keys from the same key material.</t>
<t>Because KeyGen is deterministic, implementations MAY choose either to store the resulting SK or to store key_material and key_info and call KeyGen to derive SK when necessary.</t>

<artwork><![CDATA[SK = KeyGen(key_material, key_info, key_dst)

Inputs:

- key_material (REQUIRED), a secret octet string. See requirements
                           above.
- key_info (OPTIONAL), an octet string. Defaults to an empty string if
                       not supplied.
- key_dst (OPTIONAL), an octet string representing the domain separation
                      tag. Defaults to the octet string
                      ciphersuite_id || "KEYGEN_DST_" if not supplied.

Outputs:

- SK, a uniformly random integer such that 0 < SK < r.

Procedure:

1. if length(key_material) < 32, return INVALID
2. if length(key_info) > 65535, return INVALID
3. derive_input = key_material || I2OSP(length(key_info), 2) || key_info
4. SK = hash_to_scalar(derive_input, key_dst)
5. if SK is INVALID, return INVALID
6. return SK
]]>
</artwork>
</section>

<section anchor="public-key"><name>Public Key</name>
<t>This operation takes a secret key (SK) and outputs a corresponding public key (PK).</t>

<artwork><![CDATA[PK = SkToPk(SK)

Inputs:

- SK (REQUIRED), a secret integer such that 0 < SK < r.

Outputs:

- PK, a public key encoded as an octet string.

Procedure:

1. W = SK * BP2
2. return point_to_octets_E2(W)
]]>
</artwork>
</section>
</section>

<section anchor="bbs-signatures-interface"><name>BBS Signatures Interface</name>
<t>This section defines a BBS Signatures Interface (see <xref target="interfaces"/>), that makes use of the core operations defined in <xref target="core-operations"/>, to perform the functions of signing and verifying the signature, as well as generating and validating the BBS proof. To create the generators (see <xref target="generators"/>) it uses the <tt>create_generators</tt> operation defined in <xref target="generators-calculation"/>. Each input message is an octet string (see <xref target="messages"/>). To map the messages to scalars, it uses the <tt>messages_to_scalars</tt> operation defined in <xref target="messages-to-scalars"/>. Generated signatures and proofs may optionally be bound to a <tt>header</tt> value. A BBS proof may additionally be bound to a <tt>presentation_header</tt> value. See <xref target="header-and-presentation-header-usage"/> for more details on the <tt>header</tt> and <tt>presentation_header</tt> usage.</t>
<t>The <tt>api_id</tt> parameter for this Interface is defined as,</t>

<artwork><![CDATA[api_id = ciphersuite_id || "H2G_HM2S_"
]]>
</artwork>
<t>where <tt>ciphersuite_id</tt> is defined by the ciphersuite and "H2G_HM2S_" is an ASCII string comprised of 9 bytes, wherein "H2G_" refers to the identifier of the <tt>create_generators</tt> operation used (see <xref target="generators-calculation"/>) and "HM2S_" is the identifier of the used <tt>messages_to_scalars</tt> mapping (see <xref target="messages-to-scalars"/>).</t>

<section anchor="signature-generation-sign"><name>Signature Generation (Sign)</name>
<t>The Sign operation returns a BBS signature from a secret key (<tt>SK</tt>), over a <tt>header</tt> and a set of <tt>messages</tt>.</t>

<artwork><![CDATA[signature = Sign(SK, PK, header, messages)

Inputs:

- SK (REQUIRED), a secret key in the form outputted by the KeyGen
                 operation.
- PK (REQUIRED), an octet string of the form outputted by SkToPk
                 provided the above SK as input.
- header (OPTIONAL), an octet string containing context and application
                     specific information. If not supplied, it defaults
                     to the empty octet string ("").
- messages (OPTIONAL), a vector of octet strings. If not supplied, it
                       defaults to the empty array ("()").

Parameters:

- api_id, the octet string ciphersuite_id || "H2G_HM2S_", where
          ciphersuite_id is defined by the ciphersuite and "H2G_HM2S_" is
          an ASCII string comprised of 9 bytes.

Outputs:

- signature, a signature encoded as an octet string; or INVALID.

Procedure:

1. message_scalars = messages_to_scalars(messages, api_id)
2. generators = create_generators(length(messages)+1, api_id)

3. signature = CoreSign(SK, PK, generators, header, message_scalars,
                                                                 api_id)
4. if signature is INVALID, return INVALID
5. return signature
]]>
</artwork>
</section>

<section anchor="signature-verification-verify"><name>Signature Verification (Verify)</name>
<t>The Verify operation validates a BBS signature, given a public key (<tt>PK</tt>), a <tt>header</tt> and a set of <tt>messages</tt>.</t>

<artwork><![CDATA[result = Verify(PK, signature, header, messages)

Inputs:

- PK (REQUIRED), an octet string of the form outputted by the SkToPk
                 operation.
- signature (REQUIRED), an octet string of the form outputted by the
                        Sign operation.
- header (OPTIONAL), an octet string containing context and application
                     specific information. If not supplied, it defaults
                     to the empty octet string ("").
- messages (OPTIONAL), a vector of octet strings. If not supplied, it
                       defaults to the empty array ("()").

Parameters:

- api_id, the octet string ciphersuite_id || "H2G_HM2S_", where
          ciphersuite_id is defined by the ciphersuite and "H2G_HM2S_" is
          an ASCII string comprised of 9 bytes.

Outputs:

- result, either VALID or INVALID.

Procedure:

1. message_scalars = messages_to_scalars(messages, api_id)
2. generators = create_generators(length(messages)+1, api_id)

3. result = CoreVerify(PK, signature, generators, header,
                                         message_scalars, api_id)
4. return result
]]>
</artwork>
</section>

<section anchor="proof-generation-proofgen"><name>Proof Generation (ProofGen)</name>
<t>The <tt>ProofGen</tt> operation creates a BBS proof, which is a zero-knowledge, proof-of-knowledge of a BBS signature, while optionally disclosing any subset of the signed messages. Validating the proof (see <tt>ProofVerify</tt> defined in <xref target="proof-verification-proofverify"/>) guarantees authenticity and integrity of the <tt>header</tt> and disclosed messages, as well as knowledge of a valid BBS signature.</t>
<t>Other than the Signer's public key (PK), the BBS signature and the signed <tt>header</tt> and messages, the operation also accepts a <tt>presentation_header</tt> value. That value, chosen by the Prover, will also be integrity protected (signed) by the resulting proof (see <xref target="header-and-presentation-header-usage"/>). Finally, to indicate which of the messages should be disclosed, the operation accepts a list of integers in ascending order, representing the indexes of those messages.</t>

<artwork><![CDATA[proof = ProofGen(PK, signature, header, ph, messages, disclosed_indexes)

Inputs:

- PK (REQUIRED), an octet string of the form outputted by the SkToPk
                 operation.
- signature (REQUIRED), an octet string of the form outputted by the
                        Sign operation.
- header (OPTIONAL), an octet string containing context and application
                     specific information. If not supplied, it defaults
                     to the empty octet string ("").
- ph (OPTIONAL), an octet string containing the presentation_header. If
                 not supplied, it defaults to the empty octet
                 string ("").
- messages (OPTIONAL), a vector of octet strings. If not supplied, it
                       defaults to the empty array ("()").
- disclosed_indexes (OPTIONAL), vector of unsigned integers in ascending
                                order. Indexes of disclosed messages. If
                                not supplied, it defaults to the empty
                                array ("()").

Parameters:

- api_id, the octet string ciphersuite_id || "H2G_HM2S_", where
          ciphersuite_id is defined by the ciphersuite and "H2G_HM2S_" is
          an ASCII string comprised of 9 bytes.

Outputs:

- proof, an octet string; or INVALID.

Procedure:

1. message_scalars = messages_to_scalars(messages, api_id)
2. generators = create_generators(length(messages) + 1, api_id)

3. proof = CoreProofGen(PK, signature, generators, header, ph,
                             message_scalars, disclosed_indexes, api_id)
4. if proof is INVALID, return INVALID
5. return proof
]]>
</artwork>
</section>

<section anchor="proof-verification-proofverify"><name>Proof Verification (ProofVerify)</name>
<t>The <tt>ProofVerify</tt> operation validates a BBS proof, given the Signer's public key (<tt>PK</tt>), a <tt>header</tt> and <tt>presentation_header</tt> values, the disclosed messages and the indexes those messages had in the original vector of signed messages.</t>

<artwork><![CDATA[result = ProofVerify(PK, proof, header, ph,
                     disclosed_messages,
                     disclosed_indexes)

Inputs:

- PK (REQUIRED), an octet string of the form outputted by the SkToPk
                 operation.
- proof (REQUIRED), an octet string of the form outputted by the
                    ProofGen operation.
- header (OPTIONAL), an optional octet string containing context and
                     application specific information. If not supplied,
                     it defaults to the empty octet string ("").
- ph (OPTIONAL), an octet string containing the presentation_header. If
                 not supplied, it defaults to the empty octet
                 string ("").
- disclosed_messages (OPTIONAL), a vector of octet strings. If not
                                 supplied, it defaults to the empty
                                 array ("()").
- disclosed_indexes (OPTIONAL), vector of unsigned integers in ascending
                                order. Indexes of disclosed messages. If
                                not supplied, it defaults to the empty
                                array ("()").

Parameters:

- api_id, the octet string ciphersuite_id || "H2G_HM2S_", where
          ciphersuite_id is defined by the ciphersuite and "H2G_HM2S_" is
          an ASCII string comprised of 9 bytes.
- (octet_point_length, octet_scalar_length), defined by the ciphersuite.

Outputs:

- result, either VALID or INVALID.

Deserialization:

1. proof_len_floor = 3 * octet_point_length + 4 * octet_scalar_length
2. if length(proof) < proof_len_floor, return INVALID
3. U = floor((length(proof) - proof_len_floor) / octet_scalar_length)
4. R = length(disclosed_indexes)

Procedure:

1. message_scalars = messages_to_scalars(disclosed_messages, api_id)
2. generators = create_generators(U + R + 1, api_id)

3. result = CoreProofVerify(PK, proof, generators, header, ph,
                             message_scalars, disclosed_indexes, api_id)
4. return result
]]>
</artwork>
</section>
</section>

<section anchor="core-operations"><name>Core Operations</name>
<t>The operations defined in this section perform the low-level cryptographic functionality of BBS Signatures. Those core functions MUST only be invoked by an Application Interface that conform to the requirements outlined in <xref target="defining-new-interfaces"/>.</t>
<t>The operations of this section make use of functions and sub-routines defined in <eref target="#utility-operations">Utility Operations</eref>. More specifically,</t>

<ul spacing="compact">
<li><tt>hash_to_scalar</tt> is defined in <xref target="hash-to-scalar"/></li>
<li><tt>calculate_domain</tt> is defined in <xref target="domain-calculation"/>.</li>
<li><tt>serialize</tt>, <tt>signature_to_octets</tt>, <tt>octets_to_signature</tt>, <tt>proof_to_octets</tt>, <tt>octets_to_proof</tt> and <tt>octets_to_pubkey</tt> are defined in <xref target="serialization"/>.</li>
<li><tt>h</tt> is the pairing operation used (see <xref target="notation"/>), defined as part of the ciphersuite.</li>
</ul>
<t>Each core operation will accept a vector of <tt>generators</tt> (points of G1) and optionally, a vector of <tt>messages</tt>. The generators MUST be unique and pseudo-random i.e., with no known relationship to each other. See <xref target="defining-new-generators"/> for more details. Each message is represented as a scalar value. See <xref target="messages-to-scalars"/> for ways to map a message to a scalar and the corresponding security requirements.</t>
<t>Furthermore, all core operations accept the Signer's public key (<tt>PK</tt>) as well as an optional octet string representing an Interface identifier (<tt>api_id</tt>).</t>
<t><strong>Note</strong> Some of the utility functions used by the core operations of this section could fail (ABORT). In that case, the calling operation MUST also immediately abort.</t>

<section anchor="coresign"><name>CoreSign</name>
<t>This operation computes a deterministic signature from a secret key (<tt>SK</tt>), a set of <tt>generators</tt> (points of G1) and optionally a <tt>header</tt> and a vector of <tt>messages</tt>. Note that signature generation is deterministic, in contrast to the academic literature, where signature generation, and more specifically the calculation of the <tt>e</tt> value (Procedure step 2 below), is randomized (i.e., the <tt>e</tt> value is drawn at random, instead of been deterministically calculated by hashing the Signer's secret key and the list of messages). This alteration protects the scheme (at least the signature generation part) from vulnerabilities related to bad entropy sources, as well as some of the the best currently known attacks, as suggested in <xref target="TZ23"/>. Additionally, it makes testing of the <tt>CoreSign</tt> operation easier, as it avoids the need for a mocked random scalar.</t>

<artwork><![CDATA[signature = CoreSign(SK, PK, generators, header, messages, api_id)

Inputs:

- SK (REQUIRED), a secret key in the form outputted by the KeyGen
                 operation.
- PK (REQUIRED), an octet string of the form outputted by SkToPk
                 provided the above SK as input.
- generators (REQUIRED), vector of pseudo-random points in G1.
- header (OPTIONAL), an octet string containing context and application
                     specific information. If not supplied, it defaults
                     to the empty octet string ("").
- messages (OPTIONAL), a vector of scalars representing the messages.
                       If not supplied, it defaults to the empty
                       array ("()").
- api_id (OPTIONAL), an octet string. If not supplied it defaults to the
                     empty octet string ("").

Parameters:

- P1, fixed point of G1, defined by the ciphersuite.

Outputs:

- signature, a vector comprised of a point of G1 and a scalar.

Definitions:

1. hash_to_scalar_dst, an octet string representing the domain
                       separation tag: api_id || "H2S_" where "H2S_" is
                       an ASCII string comprised of 4 bytes.

Deserialization:

1. L = length(messages)
2. if length(generators) != L + 1, return INVALID
3. (msg_1, ..., msg_L) = messages
4. (Q_1, H_1, ..., H_L) = generators

Procedure:

1. domain = calculate_domain(PK, Q_1, (H_1, ..., H_L), header, api_id)

2. e = hash_to_scalar(serialize((SK, msg_1, ..., msg_L, domain)),
                                                     hash_to_scalar_dst)
3. B = P1 + Q_1 * domain + H_1 * msg_1 + ... + H_L * msg_L
4. A = B * (1 / (SK + e))
5. return signature_to_octets((A, e))
]]>
</artwork>
<t><strong>Note</strong> When computing step 4 of the above procedure there is an extremely small probability (around <tt>2^(-r)</tt>) that the condition <tt>(SK + e) = 0 mod r</tt> will be met. How implementations evaluate the inverse of the scalar value <tt>0</tt> may vary, with some returning an error and others returning <tt>0</tt> as a result. If the returned value from the inverse operation <tt>1/(SK + e)</tt> does evaluate to <tt>0</tt> the value of <tt>A</tt> will equal <tt>Identity_G1</tt> thus an invalid signature. Implementations MAY elect to check <tt>(SK + e) = 0 mod r</tt> prior to step 4, and or <tt>A != Identity_G1</tt> after step 4 to prevent the production of invalid signatures.</t>
</section>

<section anchor="coreverify"><name>CoreVerify</name>
<t>This operation checks that a signature is valid for a given set of <tt>generators</tt>, <tt>header</tt> and vector of <tt>messages</tt>, against a supplied public key (<tt>PK</tt>). The set of messages MUST be supplied in this operation in the same order they were supplied to <tt>CoreSign</tt> (<xref target="coresign"/>) when creating the signature.</t>

<artwork><![CDATA[result = CoreVerify(PK, signature, generators, header, messages, api_id)

Inputs:

- PK (REQUIRED), an octet string of the form outputted by the SkToPk
                 operation.
- signature (REQUIRED), an octet string of the form outputted by the
                        Sign operation.
- generators (REQUIRED), vector of pseudo-random points in G1.
- header (OPTIONAL), an octet string containing context and application
                     specific information. If not supplied, it defaults
                     to the empty octet string ("").
- messages (OPTIONAL), a vector of scalars representing the messages.
                       If not supplied, it defaults to the empty
                       array ("()").
- api_id (OPTIONAL), an octet string. If not supplied it defaults to the
                     empty octet string ("").

Parameters:

- P1, fixed point of G1, defined by the ciphersuite.

Outputs:

- result, either VALID or INVALID.

Deserialization:

1. signature_result = octets_to_signature(signature)
2. if signature_result is INVALID, return INVALID
3. (A, e) = signature_result
4. W = octets_to_pubkey(PK)
5. if W is INVALID, return INVALID
6. L = length(messages)
7. if length(generators) != L + 1, return INVALID
8. (msg_1, ..., msg_L) = messages
9. (Q_1, H_1, ..., H_L) = generators

Procedure:

1. domain = calculate_domain(PK, Q_1, (H_1, ..., H_L), header, api_id)
2. B = P1 + Q_1 * domain + H_1 * msg_1 + ... + H_L * msg_L
3. if h(A, W) * h(A * e - B, BP2) != Identity_GT, return INVALID
4. return VALID
]]>
</artwork>
</section>

<section anchor="coreproofgen"><name>CoreProofGen</name>
<t>This operation computes a zero-knowledge proof-of-knowledge of a signature, while optionally selectively disclosing from the original set of signed messages. The Prover may also supply a <tt>presentation_header</tt> (denoted as <tt>ph</tt> on the input definitions of the <tt>CoreProofGen</tt> operation). See <xref target="header-and-presentation-header-usage"/> for more details. Validating the resulting proof (using the <tt>CoreProofVerify</tt> algorithm defined in <xref target="coreproofverify"/>), guarantees the integrity and authenticity of the revealed messages, as well as the possession of a valid signature (for the public key <tt>PK</tt>) by the Prover. See <xref target="proof-generation-and-verification-algorithmic-explanation"/> for a high level explanation on the inner-workings of the algorithm.</t>
<t>The <tt>CoreProofGen</tt> operation will accept that signature as an input. It is RECOMMENDED to validate that signature, using the inputted public key <tt>PK</tt> and <tt>generators</tt> set, against the supplied <tt>messages</tt> and <tt>header</tt>, with the <tt>CoreVerify</tt> operation defined in <xref target="coreverify"/>.</t>
<t>The messages supplied in this operation MUST be in the same order as when supplied to <tt>CoreSign</tt> (<xref target="coresign"/>). To specify which of those messages will be disclosed, the Prover can supply the list of indexes (<tt>disclosed_indexes</tt>) that the disclosed messages have in the array of signed messages. Each element in <tt>disclosed_indexes</tt> MUST be a non-negative integer, in the range from 0 to <tt>length(messages) - 1</tt>.</t>
<t>The operation works by first calculating a set of random scalars using the <tt>calculate_random_scalars</tt> operation defined in <xref target="random-scalars"/>, utilized to blind the signature and the undisclosed messages (see <xref target="randomness-requirements"/> for considerations and requirements on random scalars generation). It then initializes the proof using the <tt>ProofInit</tt> subroutine defined in <xref target="proof-initialization"/>. The result will be passed to the challenge calculation operation (<tt>ProofChallengeCalculate</tt>, defined in <xref target="challenge-calculation"/>). The outputted challenge, together with the initialization result, will be used by the <tt>ProofFinalize</tt> subroutine defined in <xref target="proof-finalization"/>, which will return the proof value.</t>

<artwork><![CDATA[proof = CoreProofGen(PK, signature, generators, header, ph, messages,
                                              disclosed_indexes, api_id)

Inputs:

- PK (REQUIRED), an octet string of the form outputted by the SkToPk
                 operation.
- signature (REQUIRED), an octet string of the form outputted by the
                        Sign operation.
- generators (REQUIRED), vector of pseudo-random points in G1.
- header (OPTIONAL), an octet string containing context and application
                     specific information. If not supplied, it defaults
                     to the empty octet string ("").
- ph (OPTIONAL), an octet string containing the presentation_header. If
                 not supplied, it defaults to the empty octet
                 string ("").
- messages (OPTIONAL), a vector of scalars representing the messages.
                       If not supplied, it defaults to the empty
                       array ("()").
- disclosed_indexes (OPTIONAL), vector of non-negative integers in
                                ascending order. Indexes of disclosed
                                messages. If not supplied, it defaults
                                to the empty array ("()").
- api_id (OPTIONAL), an octet string. If not supplied it defaults to the
                     empty octet string ("").

Outputs:

- proof, an octet string; or INVALID.

Deserialization:

1.  signature_result = octets_to_signature(signature)
2.  if signature_result is INVALID, return INVALID
3.  (A, e) = signature_result

4.  L = length(messages)
5.  R = length(disclosed_indexes)
6.  if R > L, return INVALID
7.  U = L - R
8.  for i in disclosed_indexes, if i < 0 or i > L - 1, return INVALID
9.  undisclosed_indexes = (0, 1, ..., L - 1) \ disclosed_indexes
10. (i1, ..., iR) = disclosed_indexes
11. (j1, ..., jU) = undisclosed_indexes

12. disclosed_messages = (messages[i1], ..., messages[iR])
13. undisclosed_messages = (messages[j1], ..., messages[jU])

Procedure:

1. random_scalars = calculate_random_scalars(5+U)
2. init_res = ProofInit(PK,
                        signature_result,
                        generators,
                        random_scalars,
                        header,
                        messages,
                        undisclosed_indexes,
                        api_id)
3. if init_res is INVALID, return INVALID
4. challenge = ProofChallengeCalculate(init_res, disclosed_messages,
                                                 disclosed_indexes,
                                                 ph,
                                                 api_id)
5. if challenge is INVALID, return INVALID
6. proof = ProofFinalize(init_res, challenge, e, random_scalars,
                                                   undisclosed_messages)
7. return proof
]]>
</artwork>
</section>

<section anchor="coreproofverify"><name>CoreProofVerify</name>
<t>This operation checks that a <tt>proof</tt> is valid for a <tt>header</tt>, vector of disclosed messages (<tt>disclosed_messages</tt>) along side their index corresponding to their original position when signed (<tt>disclosed_indexes</tt>) and <tt>presentation_header</tt> (denoted as <tt>ph</tt> on the input definitions of the <tt>CoreProofVerify</tt> operation) against a public key (<tt>PK</tt>).</t>
<t>The inputted disclosed messages (<tt>disclosed_messages</tt>) MUST be supplied to this operation in the same order as they had as part of the <tt>messages</tt> input of the <tt>CoreSign</tt> operation defined in <xref target="coresign"/>. Similarly, the indexes of the disclosed messages (<tt>disclosed_indexes</tt>) MUST be the same and in the same order as the <tt>disclosed_indexes</tt> input of <tt>CoreProofGen</tt> (<xref target="coreproofgen"/>). Failure to comply with these requirements will result to the proof verification procedure returning INVALID.</t>
<t>The operation works by first initializing the proof verification procedure using the <tt>ProofVerifyInit</tt> subroutine defined in <xref target="proof-verification-initialization"/>. The result will be inputted to the challenge calculation operation (<tt>ProofChallengeCalculate</tt>, defined in <xref target="challenge-calculation"/>). The resulting challenge and the two first components of the received proof (points of G1) will be checked for correctness (steps 5 and 6 in the following procedure), to verify the proof.</t>

<artwork><![CDATA[result = CoreProofVerify(PK, proof, generators, header, ph,
                          disclosed_messages, disclosed_indexes, api_id)

Inputs:

- PK (REQUIRED), an octet string of the form outputted by the SkToPk
                 operation.
- proof (REQUIRED), an octet string of the form outputted by the
                    ProofGen operation.
- generators (REQUIRED), vector of pseudo-random points in G1.
- header (OPTIONAL), an optional octet string containing context and
                     application specific information. If not supplied,
                     it defaults to the empty octet string ("").
- ph (OPTIONAL), an octet string containing the presentation_header. If
                 not supplied, it defaults to the empty octet
                 string ("").
- disclosed_messages (OPTIONAL), a vector of scalars representing the
                                 messages. If not supplied, it defaults
                                 to the empty array ("()").
- disclosed_indexes (OPTIONAL), vector of non-negative integers in
                                ascending order. Indexes of disclosed
                                messages. If not supplied, it defaults
                                to the empty array ("()").
- api_id (OPTIONAL), an octet string. If not supplied it defaults to the
                     empty octet string ("").

Parameters:

- P1, fixed point of G1, defined by the ciphersuite.

Outputs:

- result, either VALID or INVALID.

Deserialization:

1. proof_result = octets_to_proof(proof)
2. if proof_result is INVALID, return INVALID
3. (Abar, Bbar, D, e^, r1^, r3^, commitments, cp) = proof_result
4. W = octets_to_pubkey(PK)
5. if W is INVALID, return INVALID

Procedure:

1. init_res = ProofVerifyInit(PK, proof_result, generators, header,
                                                disclosed_messages,
                                                disclosed_indexes,
                                                api_id)
2. if init_res is INVALID, return INVALID
3. challenge = ProofChallengeCalculate(init_res, disclosed_messages,
                                       disclosed_indexes, ph, api_id)
4. if challenge is INVALID, return INVALID
5. if cp != challenge, return INVALID
6. if h(Abar, W) * h(Bbar, -BP2) != Identity_GT, return INVALID
7. return VALID
]]>
</artwork>
</section>
</section>

<section anchor="proof-protocol-subroutines"><name>Proof Protocol Subroutines</name>
<t>This section describes the subroutines used by the <tt>CoreProofGen</tt> (<xref target="coreproofgen"/>) and <tt>CoreProofVerify</tt> (<xref target="coreproofverify"/>) operations. See <xref target="proof-generation-and-verification-algorithmic-explanation"/>, for a high-level intuitive overview of the procedure used to generate and verify a BBS proof.</t>

<section anchor="proof-initialization"><name>Proof Initialization</name>
<t>This operation initializes the proof and returns one of the inputs passed to the challenge calculation operation (i.e., <tt>ProofChallengeCalculate</tt>, <xref target="challenge-calculation"/>), during the <tt>CoreProofGen</tt> operation defined in <xref target="coreproofgen"/>.</t>
<t>The inputted <tt>messages</tt> MUST be supplied to this operation in the same order they had when inputted to the <tt>CoreSign</tt> operation (<xref target="coresign"/>).</t>
<t>The defined procedure needs the messages the Prover decided to not disclose. For this purpose, along the list of signed messages, the operation also accepts a set of integers in the range from <tt>0</tt> to <tt>length(messages) - 1</tt> (inclusive) in ascending order, representing the indexes of the undisclosed messages (<tt>undisclosed_indexes</tt>). To blind the inputted <tt>signature</tt> and the undisclosed messages, the operation will also accept a set of uniformly random scalars (<tt>random_scalars</tt>). This set must have exactly 5 more items than the list of undisclosed indexes (i.e., it must hold that <tt>length(random_scalars) = length(undisclosed_indexes) + 5</tt>).</t>
<t>This operation makes use of the <tt>calculate_domain</tt> function defined in <xref target="domain-calculation"/>.</t>

<artwork><![CDATA[init_res = ProofInit(PK, signature, generators, random_scalars,
                          header, messages, undisclosed_indexes, api_id)

Inputs:

- PK (REQUIRED), an octet string of the form outputted by the SkToPk
                 operation.
- signature (REQUIRED), vector representing a BBS signature, consisting
                        of a point of G1 and a scalar, in that order.
- generators (REQUIRED), vector of points in G1.
- random_scalars (REQUIRED), vector of scalar values.
- header (OPTIONAL), octet string. If not supplied it defaults to the
                     empty octet string ("").
- messages (OPTIONAL), vector of scalar values. If not supplied, it
                       defaults to the empty array ("()").
- undisclosed_indexes (OPTIONAL), vector of non-negative integers in
                                  ascending order. If not supplied, it
                                  defaults to the empty array ("()").
- api_id (OPTIONAL), an octet string. If not supplied it defaults to the
                     empty octet string ("").

Parameters:

- P1, fixed point of G1, defined by the ciphersuite.

Outputs:

- init_res, vector consisting of 5 points of G1 and a scalar, in that
            order; or INVALID.

Deserialization:

1.  (A, e) = signature
2.  L = length(messages)
3.  U = length(undisclosed_indexes)
4.  (j1, ..., jU) = undisclosed_indexes
5.  if length(random_scalars) != U + 5, return INVALID
6.  (r1, r2, e~, r1~, r3~, m~_j1, ..., m~_jU) = random_scalars
7.  (msg_1, ..., msg_L) = messages

8.  if length(generators) != L + 1, return INVALID
9.  (Q_1, MsgGenerators) = generators
10. (H_1, ..., H_L) = MsgGenerators
11. (H_j1, ..., H_jU) = (MsgGenerators[j1], ..., MsgGenerators[jU])

ABORT if:

1. for i in undisclosed_indexes, i < 0 or i > L - 1
2. U > L

Procedure:

1. domain = calculate_domain(PK, Q_1, (H_1, ..., H_L), header, api_id)

2. B = P1 + Q_1 * domain + H_1 * msg_1 + ... + H_L * msg_L
3. D = B * r2
4. Abar = A * (r1 * r2)
5. Bbar = D * r1 - Abar * e

6. T1 = Abar * e~ + D * r1~
7. T2 = D * r3~ + H_j1 * m~_j1 + ... + H_jU * m~_jU

8. return (Abar, Bbar, D, T1, T2, domain)
]]>
</artwork>
</section>

<section anchor="proof-finalization"><name>Proof Finalization</name>
<t>This operation finalizes the proof calculation during the <tt>CoreProofGen</tt> operation defined in <xref target="coreproofgen"/> and returns the serialized proof value.</t>
<t>As inputs, this operation accepts the proof initialization result as returned by the <tt>ProofInit</tt> operation defined in <xref target="proof-initialization"/> (<tt>init_res</tt>) as well as a scalar value representing the proof's <tt>challenge</tt> as calculated by the <tt>ProofChallengeCalculate</tt> operation defined in <xref target="challenge-calculation"/>. It also requires the scalar part of the BBS signature (<tt>e_value</tt>), the random scalars used to generate the proof (<tt>random_scalars</tt>, as inputted to the <tt>ProofInit</tt> operation) and a set of scalars, representing the messages the Prover decided to not disclose (<tt>undisclosed_messages</tt>). Those messages MUST be supplied to this operation in the same order as they had as part of the <tt>messages</tt> input of the <tt>CoreSign</tt> operation (<xref target="coresign"/>).</t>
<t>This operation makes use of the <tt>proof_to_octets</tt> function defined in <xref target="proof-to-octets"/>.</t>

<artwork><![CDATA[proof = ProofFinalize(init_res, challenge, e_value, random_scalars,
                                                   undisclosed_messages)

Inputs:

- init_res (REQUIRED), vector representing the value returned after
                       initializing the proof generation or verification
                       operations, consisting of 5 points of G1 and a
                       scalar value, in that order.
- challenge (REQUIRED), scalar value.
- e_value (REQUIRED), scalar value.
- random_scalars (REQUIRED), vector of scalar values.
- undisclosed_messages (OPTIONAL), vector of scalar values. If not
                                   supplied, it defaults to the empty
                                   array ("()").

Outputs:

- proof, an octet string; or INVALID.

Deserialization:

1. U = length(undisclosed_messages)
2. if length(random_scalars) != U + 5, return INVALID
3. (r1, r2, e~, r1~, r3~, m~_j1, ..., m~_jU) = random_scalars
4. (undisclosed_1, ..., undisclosed_U) = undisclosed_messages
5. (Abar, Bbar, D) = (init_res[0], init_res[1], init_res[2])

Procedure:

1. r3 = r2^-1 (mod r)

2. e^ = e~ + e_value * challenge
3. r1^ = r1~ - r1 * challenge
4. r3^ = r3~ - r3 * challenge
5. for j in (1, ..., U): m^_j = m~_j + undisclosed_j * challenge (mod r)

6. proof = (Abar, Bbar, D, e^, r1^, r3^, (m^_j1, ..., m^_jU), challenge)
7. return proof_to_octets(proof)
]]>
</artwork>
</section>

<section anchor="proof-verification-initialization"><name>Proof Verification Initialization</name>
<t>This operation initializes the proof verification operation and returns part of the input that will be passed to the challenge calculation operation (i.e., <tt>ProofChallengeCalculate</tt>, <xref target="challenge-calculation"/>), during the <tt>CoreProofVerify</tt> operation defined in <xref target="coreproofverify"/>.</t>
<t>Note that, the scalars representing the disclosed messages (<tt>disclosed_messages</tt>) MUST be supplied to this operation in the same order as they had as part of the <tt>messages</tt> input of the <tt>CoreSign</tt> operation defined in <xref target="coresign"/> (otherwise, proof verification will fail). Similarly, the indexes of the disclosed messages in the set of signed messages MUST be supplied to this operation as a set of integers in accenting order (<tt>disclosed_indexes</tt>).</t>
<t>This operation makes use of the <tt>calculate_domain</tt> function defined in <xref target="domain-calculation"/>.</t>

<artwork><![CDATA[init_res = ProofVerifyInit(PK,
                           proof,
                           generators,
                           header,
                           disclosed_messages,
                           disclosed_indexes,
                           api_id)

Inputs:

- PK (REQUIRED), an octet string of the form outputted by the SkToPk
                 operation.
- proof (REQUIRED), vector representing a BBS proof, consisting of 3
                    points of G1, 3 scalars, another nested but possibly
                    empty vector of scalars and another scalar, in that
                    order.
- generators (REQUIRED), vector of points in G1.
- header (OPTIONAL), octet string. If not supplied it defaults to the
                     empty octet string ("").
- disclosed_messages (OPTIONAL), vector of scalar values. If not
                                 supplied, it defaults to the empty
                                 array ("()").
- disclosed_indexes (OPTIONAL), vector of non-negative integers in
                                ascending order. If not supplied, it
                                defaults to the empty array ("()").
- api_id (OPTIONAL), an octet string. If not supplied it defaults to the
                     empty octet string ("").

Parameters:

- P1, fixed point of G1, defined by the ciphersuite.

Outputs:

- init_res, vector consisting of 5 points of G1 and a scalar, in that
            order.

Deserialization:

1.  (Abar, Bbar, D, e^, r1^, r3^, commitments, c) = proof
2.  U = length(commitments)
3.  R = length(disclosed_indexes)
4.  L = R + U
5.  (i1, ..., iR) = disclosed_indexes
6.  for i in disclosed_indexes, if i < 0 or i > L - 1, return INVALID
7.  (j1, ..., jU) = (0, 1, ..., L - 1) \ disclosed_indexes
8.  if length(disclosed_messages) != R, return INVALID
9.  (msg_i1, ..., msg_iR) = disclosed_messages
10. (m^_j1, ...., m^_jU) = commitments

11. if length(generators) != L + 1, return INVALID
12. (Q_1, MsgGenerators) = generators
13. (H_1, ..., H_L) = MsgGenerators
14. (H_i1, ..., H_iR) = (MsgGenerators[i1], ..., MsgGenerators[iR])
15. (H_j1, ..., H_jU) = (MsgGenerators[j1], ..., MsgGenerators[jU])

Procedure:

1. domain = calculate_domain(PK, Q_1, (H_1, ..., H_L), header, api_id)

2. T1 = Bbar * c + Abar * e^ + D * r1^
3. Bv = P1 + Q_1 * domain + H_i1 * msg_i1 + ... + H_iR * msg_iR
4. T2 = Bv * c + D * r3^ + H_j1 * m^_j1 + ... +  H_jU * m^_jU

5. return (Abar, Bbar, D, T1, T2, domain)
]]>
</artwork>
</section>

<section anchor="challenge-calculation"><name>Challenge Calculation</name>
<t>This operation calculates the challenge scalar value, used during the <tt>CoreProofGen</tt> (<xref target="coreproofgen"/>) and <tt>CoreProofVerify</tt> (<xref target="coreproofverify"/>), as part of the Fiat-Shamir heuristic, for making the proof protocol non-interactive (in a interactive setting, the challenge would be a random value supplied by the Verifier).</t>
<t>As inputs, this operation will accept the proof generation or verification initialization result, as outputted by the <tt>ProofInit</tt> (<xref target="proof-initialization"/>) or <tt>ProofVerifyInit</tt> (<xref target="proof-verification-initialization"/>) operations (<tt>init_res</tt>). It will additionally accept the set of scalars representing the messages the Prover disclosed (<tt>disclosed_messages</tt>) as well as the list of indexes those messages had in the vector of signed messages (<tt>disclosed_indexes</tt>), together with the <tt>presentation_header</tt> (denoted as <tt>ph</tt> on the inputs of the <tt>ProofChallengeCalculate</tt> operation).</t>
<t>At a high level, the challenge will be calculated as the digest (using <tt>hash_to_scalar</tt> defined in <xref target="hash-to-scalar"/>, to map it to a scalar value) of the following values:</t>

<ul spacing="compact">
<li>The total number of disclosed messages <tt>R</tt>.</li>
<li>Each index in the <tt>disclosed_indexes</tt> list, followed by the corresponding disclosed message (i.e., if <tt>disclosed_indexes = [i1, i2]</tt> and <tt>disclosed_messages = [msg_i1, msg_i2]</tt>, the input to the challenge digest, after <tt>R</tt>, will include <tt>i1 || msg_i1 || i2 || msg_i2</tt>).</li>
<li>The points <tt>Abar, Bbar, D, T1, T2</tt> and the <tt>domain</tt> scalar, calculated during the proof initialization phase of <tt>CoreProofGen</tt> (see <xref target="coreproofgen"/>).</li>
<li>The input <tt>presentation_header</tt> (<tt>ph</tt>) values.</li>
</ul>
<t>This operation makes use of the <tt>serialize</tt> function, defined in <xref target="serialize"/>.</t>

<artwork><![CDATA[challenge = ProofChallengeCalculate(init_res, disclosed_messages,
                                          disclosed_indexes, ph, api_id)

Inputs:
- init_res (REQUIRED), vector representing the value returned after
                       initializing the proof generation or verification
                       operations, consisting of 5 points of G1 and a
                       scalar value, in that order.
- disclosed_messages (OPTIONAL), vector of scalar values. If not
                                 supplied, it defaults to the empty
                                 array ("()").
- disclosed_indexes (OPTIONAL), vector of non-negative integers in
                                ascending order. If not supplied, it
                                defaults to the empty array ("()").
- ph (OPTIONAL), an octet string. If not supplied, it must default to
                 the empty octet string ("").
- api_id (OPTIONAL), an octet string. If not supplied it defaults to the
                     empty octet string ("").

Outputs:

- challenge, a scalar.

Definitions:

1. hash_to_scalar_dst, an octet string representing the domain
                       separation tag: api_id || "H2S_" where "H2S_" is
                       an ASCII string comprised of 4 bytes.

Deserialization:

1. R = length(disclosed_indexes)
2. (i1, ..., iR) = disclosed_indexes
3. if length(disclosed_messages) != R, return INVALID
3. (msg_i1, ..., msg_iR) = disclosed_messages
4. (Abar, Bbar, D, T1, T2, domain) = init_res

ABORT if:

1. R > 2^64 - 1
2. length(ph) > 2^64 - 1

Procedure:

1. c_arr = (R, i1, msg_i1, i2, msg_i2, ..., iR, msg_iR, Abar, Bbar,
                                                      D, T1, T2, domain)
2. c_octs = serialize(c_arr) || I2OSP(length(ph), 8) || ph
3. return hash_to_scalar(c_octs, hash_to_scalar_dst)
]]>
</artwork>
<t><strong>Note</strong>: If the <tt>presentation_header</tt> (<tt>ph</tt>) is not supplied in <tt>ProofChallengeCalculate</tt>, 8 bytes representing a length of 0 (i.e., <tt>0x0000000000000000</tt>), must still be appended after the <tt>serialize(c_arr)</tt> value, during the concatenation step of the above procedure (step 2).</t>
</section>
</section>

<section anchor="defining-new-interfaces"><name>Defining New Interfaces</name>
<t>This document defines a BBS Interface to be a set of operations that use the core functions defined in <xref target="core-operations"/>, to generate and validate BBS signatures and proofs. These core operations require a set of generators, and optionally, a set of scalars representing the messages.</t>
<t>The Interface operations are tasked with creating the generators, as well as mapping the received set of messages to a set of scalar values. The created generators MUST follow the requirements listed in <xref target="defining-new-generators"/>. If a set of messages is supplied, the mapping to scalars procedure MUST follow the requirements listed in <xref target="define-a-new-map-to-scalar"/>.</t>
<t>Each Interface MUST also define a unique identifier as a parameter, called <tt>api_id</tt>. It is RECOMMENDED from the operations that create generators and map messages to scalars, to also define a unique identifiers (see <xref target="interface-utilities"/>). Assuming that <tt>CREATE_GENERATORS_ID</tt> is the unique identifier of the operation that creates the generators and <tt>MAP_TO_SCALAR_ID</tt> is the unique identifier of the operation that maps the messages to scalars, the RECOMMENDED format for the <tt>api_id</tt> is the following:</t>

<artwork><![CDATA[ciphersuite_id || CREATE_GENERATORS_ID || MAP_TO_SCALAR_ID || ADD_INFO
]]>
</artwork>
<t>Where <tt>ciphersuite_id</tt> is defined by the ciphersuite and the <tt>ADD_INFO</tt> value is an optional octet string indicating any additional information used to uniquely qualify the Interface. When <tt>ADD_INFO</tt> is present, it MUST only contain ASCII encoded characters with codes between 0x21 and 0x7e (inclusive) and MUST end with an underscore (ASCII code: 0x5f), other than the last character the string MUST NOT contain any other underscores (ASCII code: 0x5f). The <tt>api_id</tt> value, MUST be used by all subroutines an Interface calls, to ensure proper domain separation.</t>
<t>Interfaces are meant to make it easier to use BBS Signature as part of other protocols with different requirements (for example, different types of input messages or different ways to create the generators), or to extend BBS Signatures with additional functionality (for example, using blinded messages as in <xref target="CDL16"/>). Documents defining new BBS Interfaces, other than adhering to the requirements listed in this section, should also include a detailed and peer reviewed analyses showcasing that, under reasonable cryptographic assumptions, the documented scheme is secure under the required security definitions and threat model of each protocol. In other words, Interfaces must be treated like Ciphersuites (<xref target="ciphersuites"/>), in the sense that applications should avoid creating their own, proprietary Interfaces.</t>
</section>
</section>

<section anchor="utility-operations"><name>Utility Operations</name>
<t>This section defines utility operations that are used by either the BBS Interface or the BBS Core Operations.</t>

<section anchor="interface-utilities"><name>Interface Utilities</name>
<t>This section defines the <tt>create_generators</tt> and <tt>messages_to_scalars</tt> operations that are used by the BBS Signatures Interface defined in <xref target="bbs-signatures-interface"/>. It also defines requirements for alternative operations that calculate generators and map messages to scalars.</t>
<t>It is RECOMMENDED that the <tt>create_generators</tt> and <tt>messages_to_scalars</tt> operations define a unique identifier, called <tt>CREATE_GENERATORS_ID</tt> and <tt>MAP_TO_SCALAR_ID</tt> respectively. Those identifiers will be used to construct the Interface identifier (see <xref target="defining-new-interfaces"/>).</t>

<section anchor="generators-calculation"><name>Generators Calculation</name>
<t>The <tt>create_generators</tt> procedure defines how to create a set of randomly sampled points from the G1 subgroup, called the generators. It makes use of the primitives defined in <xref target="RFC9380"/> (more specifically of <tt>hash_to_curve</tt> and <tt>expand_message</tt>) to hash a seed to a set of generators. Those primitives are implicitly defined by the ciphersuite, through the choice of a hash-to-curve suite (see the <tt>hash_to_curve_suite</tt> parameter in <xref target="ciphersuite-format"/>).</t>
<t>Since <tt>create_generators</tt> generates constant points, as an optimization, implementations MAY cache its result for a specific <tt>count</tt> (which can be arbitrarily large, depending on the application). Care must be taken, to guarantee that the generators will be fetched from the cache in the same order they had when they where created (i.e., an application should not sort or in any way rearrange the cached generators).</t>

<artwork><![CDATA[generators = create_generators(count, api_id)

Inputs:

- count (REQUIRED), unsigned integer. Number of generators to create.
- api_id (OPTIONAL), octet string. If not supplied it defaults to the
                     empty octet string ("").

Parameters:

- hash_to_curve_g1, the hash_to_curve operation for the G1 subgroup,
                    defined by the suite specified by the
                    hash_to_curve_suite parameter of the ciphersuite.
- expand_message, the expand_message operation defined by the suite
                  specified by the hash_to_curve_suite parameter of the
                  ciphersuite.
- expand_len, defined by the ciphersuite.

Outputs:

- generators, an array of generators.

Definitions:

1. seed_dst, an octet string representing the domain separation tag:
             api_id || "SIG_GENERATOR_SEED_" where "SIG_GENERATOR_SEED_"
             is an ASCII string comprised of 19 bytes.
2. generator_dst, an octet string representing the domain separation
                  tag: api_id || "SIG_GENERATOR_DST_", where
                  "SIG_GENERATOR_DST_" is an ASCII string comprised of
                  18 bytes.
3. generator_seed, an octet string representing the domain separation
                   tag: api_id || "MESSAGE_GENERATOR_SEED", where
                   "MESSAGE_GENERATOR_SEED" is an ASCII string comprised
                   of 22 bytes.

ABORT if:

1. count > 2^64 - 1

Procedure:

1. v = expand_message(generator_seed, seed_dst, expand_len)
2. for i in (1, 2, ..., count):
3.    v = expand_message(v || I2OSP(i, 8), seed_dst, expand_len)
4.    generator_i = hash_to_curve_g1(v, generator_dst)
5. return (generator_1, ..., generator_count)
]]>
</artwork>
<t>The value of <tt>v</tt> MAY also be cached in order to efficiently extend an existing list of cached generator points.</t>
<t>The <tt>CREATE_GENERATORS_ID</tt> of the above operation is define as,</t>

<artwork><![CDATA[CREATE_GENERATORS_ID = "H2G_"
]]>
</artwork>

<section anchor="defining-new-generators"><name>Defining new Generators</name>
<t>When defining a new <tt>create_generators</tt> procedure, the most important property is that the points are pseudo-randomly chosen from the G1 group, with no known relationship to each other, given reasonable assumptions and cryptographic primitives. More specifically, the required properties are</t>

<ul spacing="compact">
<li>The generators should be indistinguishable from uniformly random points of G1 (even given the knowledge of the system's public parameters, like the <tt>generator_seed</tt> value in <xref target="generators-calculation"/>). This means that given only the points <tt>H_1, ..., H_i</tt> it should be infeasible to guess <tt>H_(i+1)</tt> (or any <tt>H_j</tt> with <tt>j &gt; i</tt>), for any <tt>i</tt>. This also means that it should be infeasible to represent any of the generators as multi-exponentiation product (i.e., of the form <tt>H_i1 * a_1 + H_i2 * a_2 + ... + H_in * a_n</tt>) of any of the other generators.</li>
<li>The returned points must be unique with very high probability, that would not lessen the targeted security level of the ciphersuite. Specifically, for a security level <tt>k</tt>, the probability of a collision should be at most <tt>1/2^k</tt>.</li>
<li>The returned points must be different from the Identity point of G1 as well as the constant point <tt>P1</tt> defined by the ciphersuite.</li>
</ul>
<t>Every operation that is used to return generator points for use with the core BBS operations (<xref target="core-operations"/>), MUST return points that conform to the aforementioned rules. Such operation must also follow the rules outlined bellow,</t>

<ul spacing="compact">
<li>It MUST be deterministic and constant time for a specific number of generators.</li>
<li>It MUST use proper domain separation for both the <tt>create_generators</tt> procedure, as well as all of the internally-called procedures.</li>
</ul>
</section>
</section>

<section anchor="messages-to-scalars"><name>Messages to Scalars</name>
<t>The <tt>messages_to_scalars</tt> operation is used to map a list of messages to their respective scalar values, which are required by the core BBS operations defined in <xref target="core-operations"/>.</t>

<artwork><![CDATA[msg_scalar = messages_to_scalars(messages, api_id)

Inputs:

- messages (REQUIRED), a vector of octet strings.
- api_id (OPTIONAL), octet string. If not supplied it defaults to the
                     empty octet string ("").

Outputs:

- msg_scalars, a list of scalars.

Definitions:

1. map_dst, an octet string representing the domain separation tag:
            api_id || "MAP_MSG_TO_SCALAR_AS_HASH_" where
            "MAP_MSG_TO_SCALAR_AS_HASH_" is an ASCII string comprised of
            26 bytes.

ABORT if:

1. length(messages) > 2^64 - 1

Procedure:

1. L =  length(messages)
2. for i in (1, ..., L):
3.     msg_scalar_i = hash_to_scalar(messages[i], map_dst)
4. return (msg_scalar_1, ..., msg_scalar_L)
]]>
</artwork>
<t>The <tt>MAP_TO_SCALAR_ID</tt> of the above operation is defines as,</t>

<artwork><![CDATA[MAP_TO_SCALAR_ID = "HM2S_"
]]>
</artwork>

<section anchor="define-a-new-map-to-scalar"><name>Define a new Map to Scalar</name>
<t>The most important property that a new operation that will map a set of messages to a set of scalars must have, is that each message should be mapped to a scalar independently from all
the other messages. More specifically, the following MUST hold,</t>

<artwork><![CDATA[For every set of messages and every message msg',
let messages' be the list of messages with msg' appended at the end and
C1 = messages_to_scalars(messages').

Let also msg_prime_scalar = messages_to_scalars((msg')),
and C2 = messages_to_scalars(messages).

If we append msg_prime_scalar at the end of C2, it must always hold that
C1 == C2.
]]>
</artwork>
<t>Note that the above property ensures that if a message is mapped to a scalar on its own or as part of a set of messages, it will not affect the resulting scalar value.</t>
<t>Additionally, the new operation MUST conform to the following requirements:</t>

<ul spacing="compact">
<li>The returned scalars MUST be independent. More specifically, knowledge of any subset of the returned scalars MUST NOT reveal any information about the scalars not in that subset.</li>
<li>Unique inputs MUST result in unique outputs.</li>
<li>If the inputted vector of messages does not include any duplicates, the outputted scalars MUST NOT include any duplicates either.</li>
<li>It MUST be deterministic and constant time on the length of the inputted vector of messages.</li>
</ul>
</section>
</section>
</section>

<section anchor="core-utilities"><name>Core Utilities</name>
<t>This section defines utility procedures that are used by the Core operations defined in <xref target="core-operations"/>.</t>

<section anchor="random-scalars"><name>Random Scalars</name>
<t>This operation returns the requested number of pseudo-random scalars, using the <tt>get_random</tt> operation (see <xref target="parameters"/>). The operation makes multiple calls to <tt>get_random</tt>. It is REQUIRED that each call will be independent from each other, as to ensure independence of the returned pseudo-random scalars.</t>
<t><strong>Note</strong>: The security of the proof generation algorithm (<tt>ProofGen</tt> defined in <xref target="proof-generation-proofgen"/>) is highly dependant on the quality of the <tt>get_random</tt> function. Care must be taken to ensure that a cryptographically secure pseudo-random generator is chosen, and that its outputs are not leaked to an adversary. See also <xref target="randomness-requirements"/> for more details and guidance.</t>

<artwork><![CDATA[random_scalars = calculate_random_scalars(count)

Inputs:

- count (REQUIRED), non negative integer. The number of pseudo random
                    scalars to return.

Parameters:

- get_random, a pseudo random function with extendable output, returning
              uniformly distributed pseudo random bytes.
- expand_len, defined by the ciphersuite.

Outputs:

- random_scalars, a list of pseudo random scalars,

Procedure:

1. for i in (1, 2, ..., count):
2.     r_i = OS2IP(get_random(expand_len)) mod r
3. return (r_1, r_2, ..., r_count)
]]>
</artwork>
</section>

<section anchor="hash-to-scalar"><name>Hash to Scalar</name>
<t>This operation describes how to hash an arbitrary octet string to a scalar value in the multiplicative group of integers mod r (i.e., values in the range from  1 to r - 1).  This procedure acts as a helper function, used internally in various places within the operations described in the spec.</t>
<t>The operation takes as input an octet string representing the octet string to hash (<tt>msg</tt>) and a domain separation tag (<tt>dst</tt>). The length of the dst MUST be less than 255 octets. See section 5.3.3 of <xref target="RFC9380"/> for guidance on using larger dst values.</t>
<t><strong>Note</strong> This operation makes use of <tt>expand_message</tt> defined in <xref target="RFC9380"/>. The operation <tt>expand_message</tt> may fail (abort). In that case, <tt>hash_to_scalar</tt> MUST also ABORT.</t>

<artwork><![CDATA[hashed_scalar = hash_to_scalar(msg_octets, dst)

Inputs:

- msg_octets (REQUIRED), an octet string. The message to be hashed.
- dst (REQUIRED), an octet string representing a domain separation tag.

Parameters:

- hash_to_curve_suite, the hash to curve suite id defined by the
                       ciphersuite.
- expand_message, the expand_message operation defined by the suite
                  specified by the hash_to_curve_suite parameter.
- expand_len, defined by the ciphersuite.

Outputs:

- hashed_scalar, a scalar.

ABORT if:

- length(dst) > 255

Procedure:

1. uniform_bytes = expand_message(msg_octets, dst, expand_len)
2. return OS2IP(uniform_bytes) mod r
]]>
</artwork>
</section>

<section anchor="domain-calculation"><name>Domain Calculation</name>
<t>This operation calculates the domain value, a scalar representing the distillation of all essential contextual information for a signature. The same domain value must be calculated by all parties (the Signer, the Prover and the Verifier) for both the signature and proofs to be validated.</t>
<t>The input to the domain value includes the <tt>header</tt> value chosen by the Signer to encode any information that is required to be revealed by the Prover (such as an expiration date, or an identifier for the target audience). This is in contrast to the signed message values, which may be withheld during a proof.</t>
<t>When a signature is calculated, the domain value is combined with a specific generator point (<tt>Q_1</tt>, see <tt>CoreSign</tt> defined in <xref target="coresign"/>) to protect the integrity of the public parameters and the <tt>header</tt>.</t>
<t>This operation makes use of the <tt>serialize</tt> function, defined in <xref target="serialize"/>.</t>

<artwork><![CDATA[domain = calculate_domain(PK, Q_1, H_Points, header, api_id)

Inputs:

- PK (REQUIRED), an octet string, representing the public key of the
                 Signer of the form outputted by the SkToPk operation.
- Q_1 (REQUIRED), point of G1 (the first point returned from
                  create_generators).
- H_Points (REQUIRED), array of points of G1.
- header (OPTIONAL), an octet string. If not supplied, it must default
                     to the empty octet string ("").
- api_id (OPTIONAL), octet string. If not supplied it defaults to the
                     empty octet string ("").

Outputs:

- domain, a scalar.

Definitions:

1. hash_to_scalar_dst, an octet string representing the domain
                       separation tag: api_id || "H2S_" where "H2S_" is
                       an ASCII string comprised of 4 bytes.

Deserialization:

1. L = length(H_Points)
2. (H_1, ..., H_L) = H_Points

ABORT if:

1. length(header) > 2^64 - 1 or L > 2^64 - 1

Procedure:

1. dom_array = (L, Q_1, H_1, ..., H_L)
2. dom_octs = serialize(dom_array) || api_id
3. dom_input = PK || dom_octs || I2OSP(length(header), 8) || header
4. return hash_to_scalar(dom_input, hash_to_scalar_dst)
]]>
</artwork>
<t><strong>Note</strong>: If the <tt>header</tt> is not supplied in <tt>calculate_domain</tt>, it defaults to the empty octet string (""). This means that in the concatenation step of the above procedure (step 3), 8 bytes representing a length of 0 (i.e., <tt>0x0000000000000000</tt>), will still need to be appended at the end, even though a header value is not provided.</t>
</section>

<section anchor="serialization"><name>Serialization</name>

<section anchor="serialize"><name>Serialize</name>
<t>This operation describes how to transform multiple elements of different types (i.e., elements that are not already in a octet string format) to a single octet string (see <xref target="serializing-to-octets"/>). The inputted elements can be points, scalars (see <xref target="terminology"/>) or integers between 0 and 2^64-1. The resulting octet string will then either be used as an input to a hash function (i.e., in <tt>CoreSign</tt> <xref target="coresign"/>, <tt>CoreVerify</tt> <xref target="coreverify"/>, <tt>CoreProofGen</tt> <xref target="coreproofgen"/> and <tt>CoreProofVerify</tt> <xref target="coreproofverify"/>), or to serialize a signature or proof (see <tt>signature_to_octets</tt> <xref target="signature-to-octets"/> and  <tt>proof_to_octets</tt> <xref target="proof-to-octets"/>).</t>

<artwork><![CDATA[octets_result = serialize(input_array)

Inputs:

- input_array (REQUIRED), an array of elements to be serialized. Each
                          element must be either a point of G1 or G2, a
                          scalar, an ASCII string or an integer value
                          between 0 and 2^64 - 1.

Parameters:

- octet_scalar_length, non-negative integer. The length of a scalar
                       octet representation, defined by the ciphersuite.
- r, the prime order of the subgroups G1 and G2, defined by the
     ciphersuite.
- point_to_octets_E*, operations that serialize a point of E1 or E2 to
                      an octet string of fixed length, defined by the
                      ciphersuite.

Outputs:

- octets_result, a scalar value or INVALID.

Procedure:

1.  let octets_result be an empty octet string.
2.  for el in input_array:
3.      if el is a point of G1: el_octs = point_to_octets_E1(el)
4.      else if el is a point of G2: el_octs = point_to_octets_E2(el)
5.      else if el is a scalar: el_octs = I2OSP(el, octet_scalar_length)
6.      else if el is an integer between 0 and 2^64 - 1:
7.          el_octs = I2OSP(el, 8)
8.      else: return INVALID
9.      octets_result = octets_result || el_octs
10. return octets_result
]]>
</artwork>
</section>

<section anchor="signature-to-octets"><name>Signature to Octets</name>
<t>This operation describes how to encode a signature to an octet string.</t>
<t><em>Note</em> this operation deliberately does not perform the relevant checks on the inputs <tt>A</tt> and <tt>e</tt> because its assumed these are done prior to its invocation, e.g., as is the case with the <tt>CoreSign</tt> <xref target="coresign"/> operation.</t>

<artwork><![CDATA[signature_octets = signature_to_octets(signature)

Inputs:

- signature (REQUIRED), a valid signature, in the form (A, e), where
                        A is a point in G1 and e is a non-zero
                        scalar mod r.

Outputs:

- signature_octets, an octet string or INVALID.

Procedure:

1. (A, e) = signature
2. return serialize((A, e))
]]>
</artwork>
</section>

<section anchor="octets-to-signature"><name>Octets to Signature</name>
<t>This operation describes how to decode an octet string, validate it and return the underlying components that make up the signature.</t>

<artwork><![CDATA[signature = octets_to_signature(signature_octets)

Inputs:

- signature_octets (REQUIRED), an octet string of the form output from
                               signature_to_octets operation.

Parameters:

- octets_to_point_E1, operations that deserializes an octet string to a
                      a point of the elliptic curve E1, or INVALID,
                      defined by the ciphersuite.
- subgroup_check_G1, operation that on input a point P returns VALID if
                     P is a valid point of the G1 subgroup, otherwise it
                     returns INVALID (see (#notation)).

Outputs:

signature, a signature in the form (A, e), where A is a point in G1
           and e is a non-zero scalar mod r; or INVALID.

Procedure:

1.  expected_len = octet_point_length + octet_scalar_length
2.  if length(signature_octets) != expected_len, return INVALID
3.  A_octets = signature_octets[0..(octet_point_length - 1)]
4.  A = octets_to_point_E1(A_octets)
5.  if A is INVALID, return INVALID
6.  if A == Identity_G1, return INVALID
7.  if subgroup_check_G1(A) returns INVALID, return INVALID

8.  index = octet_point_length
9.  end_index = index + octet_scalar_length - 1
10. e = OS2IP(signature_octets[index..end_index])
11. if e = 0 or e >= r, return INVALID
12. return (A, e)
]]>
</artwork>
</section>

<section anchor="proof-to-octets"><name>Proof to Octets</name>
<t>This operation describes how to encode as an octet string, a proof as computed by <tt>CoreProofGen</tt> in <xref target="coreproofgen"/> (or, more precisely, by step 5 of the <tt>ProofFinalize</tt> operation defined in <xref target="proof-finalization"/>).</t>
<t>The inputted proof value must consist of the following components, in that order:</t>

<ol spacing="compact">
<li>Three (3) valid points of the G1 subgroup, different from the identity point of G1 (i.e., <tt>Abar, Bbar, D</tt>, in ProofGen)</li>
<li>Three (3) integers representing scalars in the range of 1 to r - 1 inclusive (i.e., <tt>e^, r1^, r3^</tt>, in ProofGen).</li>
<li>A number of integers representing scalars in the range of 1 to r - 1 inclusive, corresponding to the undisclosed from the proof messages (i.e., <tt>m^_j1, ..., m^_jU</tt>, in ProofGen, where U the number of undisclosed messages).</li>
<li>One (1) integer representing a scalar in the range 1 to r-1 inclusive (i.e., <tt>c</tt> in ProofGen).</li>
</ol>

<artwork><![CDATA[proof_octets = proof_to_octets(proof)

Inputs:

- proof (REQUIRED), a BBS proof in the form calculated by ProofGen in
                    step 27 (see above).

Outputs:

- proof_octets, an octet string or INVALID.

Procedure:

1. (Abar, Bbar, D, e^, r1^, r3^, (m^_1, ..., m^_U), c) = proof
2. return serialize((Abar, Bbar, D, e^, r1^, r3^, m^_1, ..., m^_U, c))
]]>
</artwork>
</section>

<section anchor="octets-to-proof"><name>Octets to Proof</name>
<t>This operation describes how to decode an octet string representing a proof, validate it and return the underlying components that make up the proof value.</t>
<t>The proof value outputted by this operation consists of the following components, in that order:</t>

<ol spacing="compact">
<li>Three (3) valid points of the G1 subgroup, each of which must not equal the identity point.</li>
<li>Three (3) integers representing scalars in the range of 1 to r - 1 inclusive.</li>
<li>A set of integers representing scalars in the range of 1 to r - 1 inclusive, corresponding to the undisclosed from the proof message commitments. This set can be empty (i.e., "()").</li>
<li>One (1) integer representing a scalar in the range of 1 to r - 1 inclusive, corresponding to the proof's challenge (<tt>c</tt>).</li>
</ol>

<artwork><![CDATA[proof = octets_to_proof(proof_octets)

Inputs:

- proof_octets (REQUIRED), an octet string of the form outputted from
                           the proof_to_octets operation.

Parameters:

- r, non-negative integer. The prime order of the G1 and G2 groups,
      defined by the ciphersuite.
- octet_scalar_length, non-negative integer. The length of a scalar
                       octet representation, defined by the ciphersuite.
- octet_point_length, non-negative integer. The length of a point in G1
                      octet representation, defined by the ciphersuite.
- subgroup_check_G1, operation that on input a point P returns VALID if
                     P is a valid point of the G1 subgroup, otherwise it
                     returns INVALID (see (#notation)).

Outputs:

- proof, a proof value in the form described above or INVALID

Procedure:

1.  proof_len_floor = 3 * octet_point_length + 4 * octet_scalar_length
2.  if length(proof_octets) < proof_len_floor, return INVALID

// Points (i.e., (Abar, Bbar, D) in ProofGen) de-serialization.
3.  index = 0
4.  for i in (0, 2):
5.      end_index = index + octet_point_length - 1
6.      A_i = octets_to_point_E1(proof_octets[index..end_index])
7.      if A_i is INVALID or Identity_G1, return INVALID
8.      if subgroup_check_G1(A_i) returns INVALID, return INVALID
9.      index += octet_point_length

// Scalars (i.e., (e^, r1^, r3^, m^_j1, ..., m^_jU, c) in
// ProofGen) de-serialization.
10. j = 0
11. while index < length(proof_octets):
12.     end_index = index + octet_scalar_length - 1
13.     s_j = OS2IP(proof_octets[index..end_index])
14.     if s_j = 0 or if s_j >= r, return INVALID
15.     index += octet_scalar_length
16.     j += 1

17. if index != length(proof_octets), return INVALID
18. msg_commitments = ()
19. if j > 4, set msg_commitments = (s_3, ..., s_(j-2))
20. return (A_0, A_1, A_2, s_0, s_1, s_2, msg_commitments, s_(j-1))
]]>
</artwork>
</section>

<section anchor="octets-to-public-key"><name>Octets to Public Key</name>
<t>This operation describes how to decode an octet string representing a public key, validates it and returns the corresponding point in G2. Steps 2 to 5 check if the public key is valid. As an optimization, implementations MAY cache the result of those steps, to avoid unnecessarily repeating validation for known public keys.</t>

<artwork><![CDATA[W = octets_to_pubkey(PK)

Inputs:

- PK, an octet string. A public key in the form outputted by the SkToPK
      operation

Parameters:

- subgroup_check_G2, operation that on input a point P returns VALID if
                     P is a valid point of the G2 subgroup, otherwise it
                     returns INVALID (see (#notation)).

Outputs:

- W, a valid point in G2 or INVALID

Procedure:

1. W = octets_to_point_E2(PK)
2. if W is INVALID, return INVALID
3. if subgroup_check_G2(W) is INVALID, return INVALID
4. if W == Identity_G2, return INVALID
5. return W
]]>
</artwork>
</section>
</section>
</section>
</section>

<section anchor="privacy-considerations"><name>Privacy Considerations</name>
<t>This section will go through threats to the Prover's privacy. Note that a BBS proof is unlinkable against both the Verifiers and the Signer, as well as multiple Verifiers colluding with each other and Verifiers colluding with the Signer. Bear in mind that those guarantees concern only the proof value, as outputted by the <tt>CoreProofGen</tt> (Section <xref target="coreproofgen"/>) and of course the <tt>ProofGen</tt> (Section <xref target="proof-generation-proofgen"/>) operations. Correspondingly, the unlinkability property does not include other values that a Prover could either knowingly or unknowingly provide to a Verifier. Those values can include disclosed messages of high entropy, the <tt>header</tt> and <tt>presentation_header</tt> values, their network address, or generally any information disclosed during an interaction with the Verifier having the potential to identify the user. Such threats, if exploited, could lead to correlation of the Prover's interactions with different Verifiers, resulting to fingerprinting attacks against the Prover's activity.</t>
<t>The following sections will describe possible privacy threats, resulting from such values and side channels, that could compromise the unlinkability property of the BBS proof. Note that, the following sections describe ways to minimize possible identifying information revealed during a BBS proof presentation, related to the BBS Signatures scheme. To minimize the privacy threats of an entire system, other protections may also need to be employed, for example, using an IP hiding proxy network like TOR (<xref target="DMS04"/>).</t>

<section anchor="header-and-presentation-header"><name>Header and Presentation Header</name>
<t>As mentioned in Section <xref target="header-and-presentation-header"/>, the <tt>header</tt> value is chosen by the Signer and bound to a BBS Signature and proof. Consequently, it must be revealed to the Verifier, together with a BBS proof. If that <tt>header</tt> value is chosen to have high entropy (i.e., unique per credential, Prover or small group of Provers), it can be used as a correlation vector to trace and link together all BBS proofs made by a signature bound to that <tt>header</tt> value. This will result in significantly worse privacy guarantees, by allowing adversaries to trace and link together all generated proofs bound to that <tt>header</tt> value (for example, if a random <tt>header</tt> is used during each BBS signature generation, adversaries will be able to link and trace the BBS proofs generated from that signature). The Issuer MUST choose a low entropy <tt>header</tt> value and it MUST be the same for a large number of users (Provers). Examples of acceptable values include, an application identifier, a country identifier or a low cardinality version number. Examples of unacceptable values include, random values, high cardinality expiration dates, the Prover's email address or any other identifying information.</t>
<t>On the other hand, the misuse of a <tt>presentation_header</tt>, chosen by the Prover and only bound to a BBS proof, does not incur as many privacy risks as the <tt>header</tt> value. For example, since a new <tt>presentation_header</tt> can be chosen each time a BBS proof is generated, random values are a viable choice. Still, to not break the unlinkability property, care must be taken that the <tt>presentation_header</tt> does not identify a single or small group of Provers. If the <tt>presentation_header</tt> is chosen to have high entropy (for example, to be a random value, a high accuracy locality identifier or a specific software build number), then the same value must not be used for more than one Proof generations. Note however, that even though the <tt>presentation_header</tt> can include high entropy values (as long as they are used only once), its a good practice for the Prover to avoid revealing personally identifying information (like their name, email address or phone number), to minimize the danger of correlating that information with other data sources, potentially unrelated to the specific application.</t>
</section>

<section anchor="total-number-and-index-of-signed-messages"><name>Total Number and Index of Signed Messages</name>
<t>When a Prover presents a BBS proof to a Verifier, other than the messages they decide to disclose, there are two additional pieces of information that will be revealed. First, the total number of signed messages, which can be inferred from the size of the BBS proof and the length of the disclosed messages list. Second, the indexes that the disclosed messages had in the list of signed messages (see <xref target="proof-generation-proofgen"/>). This information, if unique to each Prover, could be employed to correlate multiple proof presentations together. As a result, the Signer should not sign lists of messages with unique lengths or unique indexing. For this reason, it is RECOMMENDED that signed lists of messages are padded to a common length (using either random, or an unused by the application message, like 0 or 1). It is also RECOMMENDED that a constant ordering of messages will be preserved when possible. For example, if an application creates signatures for the messages <tt>[&lt;user_name&gt;, &lt;user_affiliation&gt;, &lt;user_country&gt;]</tt>, then those messages should always be signed in the same order, i.e., first message should always be the user's name (<tt>&lt;user_name&gt;</tt>), second message should always be the user's affiliation (<tt>&lt;user_affiliation&gt;</tt>) and the last message should always be the user's country of origins (<tt>&lt;user_country&gt;</tt>). Provers can employ consistency validation mechanisms, like the ones described in <xref target="I-D.ietf-privacypass-key-consistency"/>, to validate that those values are not used to correlate them.</t>
</section>

<section anchor="signer-public-keys"><name>Signer Public Keys</name>
<t>As with most systems based on public key cryptography, multiple BBS signatures (and the subsequent BBS proofs) could be correlated with each other, if the Signer does not use the same key for a large set of produced signatures. For example, the Signer could use a different key to generate the signatures intended for a specific user, or a small set of users. Every proof generated by that set of users would then be linked to that group (since it will be validated by a different public key). To avoid fragmentation of the user space by different public keys, an application could use the same mechanisms that where proposed to check the consistency of the total number of messages and their indexes (i.e., <xref target="I-D.ietf-privacypass-key-consistency"/>, see <xref target="total-number-and-index-of-signed-messages"/>).</t>
</section>

<section anchor="disclosed-messages"><name>Disclosed Messages</name>
<t>Although multiple BBS proofs cannot be linked to each other, privacy also depends on the uniqueness of the disclosed messages during proof generation. If a unique message (or unique combination of messages) is revealed multiple times, it could be used to link the corresponding proofs together. Examples of such messages include full names, government IDs, email addresses and phone numbers. If not required by the use case, the Prover should avoid disclosing such information when constructing a BBS proof.</t>
<t>For certain types of message values, set membership proofs (for example, <xref target="VB22"/>) or range proofs (for example, <xref target="BBB17"/>) could be used to further mitigate the above issue. With a set membership proof, the BBS proof Verifier will be able to validate that one of the Prover's signed (and undisclosed) messages, belongs to a pre-defined set (for example that the Prover's government ID belongs to a set of valid government IDs). The inverse is also possible, where the Prover showcases that one of the undisclosed messages is not part of a set (for example, that a signed unique revocation identifier is not part of the set of revoked identifiers). If a message is represented by a numeric value (see <xref target="mapping-messages-to-scalars"/>), range proofs can be used to prove that it is within a specific range. As an example, a Prover, instead of revealing their age, they could use a range proof to showcase that they are over 18 years old.</t>
</section>
</section>

<section anchor="security-considerations"><name>Security Considerations</name>

<section anchor="validating-public-keys"><name>Validating Public Keys</name>
<t>Note that all core operations as defined in <xref target="core-operations"/> expect the Signer's public key as input. It is RECOMMENDED for all those operations, that they deserialize the public key first using the <tt>octets_to_pubkey</tt> procedure defined in <xref target="octets-to-public-key"/>, even if they only require the octet string representation of the public key. If the <tt>octets_to_pubkey</tt> procedure returns INVALID, the calling operation should also return INVALID and abort. This recommendation applies to the <tt>CoreSign</tt> (<xref target="coresign"/>) and <tt>CoreProofGen</tt> (<xref target="coreproofgen"/>) operations. An explicit invocation to the <tt>octets_to_pubkey</tt> operation is already defined and therefore required in the <tt>CoreVerify</tt> (<xref target="coreverify"/>) and <tt>CoreProofVerify</tt> (<xref target="coreproofverify"/>) operations. If the required checks for the validity of the Signer's public key are not performed, the results are unpredictable, leading to unexpected vulnerabilities (for example, the output of the pairing operation on input of an invalid elliptic curve point can be highly irregular and implementation-dependent, with some returning the identity point of the elliptic curve and others returning errors).</t>
</section>

<section anchor="skipping-membership-checks"><name>Skipping Membership Checks</name>
<t>The subgroup check <tt>subgroup_check_G*</tt> invocation during either signature deserialization (<tt>octets_to_signature</tt>, defined in <xref target="octets-to-signature"/>), proof deserialization (<tt>octets_to_proof</tt>, defined in <xref target="octets-to-proof"/>) or public key deserialization (<tt>octets_to_pubkey</tt>, define in <xref target="octets-to-public-key"/>) is REQUIRED by all implementations. Failure to comply would lead to unpredicted behavior and vulnerabilities. Note that some libraries implementing the pairing-friendly curves functionality, may incorporate that check as part of a <tt>octets_to_point_G1</tt> or <tt>octet_to_point_G2</tt> operation (i.e., operations that both deserialize an octet string to get an elliptic curve point and then check if the resulting point is part of the <tt>G1</tt> or <tt>G2</tt> group accordingly). In those cases, the implementer must make sure that those checks are executed correctly.</t>
<t>Note that checking that the points are in the correct subgroup is essential to avoid possible forgeries of a BBS signature or proof (<xref target="ADR02"/>). Furthermore, the pairing operation <xref target="notation"/> is undefined when its input points are not in <tt>G1</tt> and <tt>G2</tt>. As a result, applications MUST execute all the subgroup checks defined by this document.</t>
</section>

<section anchor="side-channel-attacks"><name>Side Channel Attacks</name>
<t>There are two places where side channel attacks could be relevant in the BBS Signatures scheme. First, against the Signer, where side channel leakage during signature generation could reveal their secret key. Second, against the Prover, where a side channel attack could be used during proof generation to either directly reveal the undisclosed messages and signature value, or reveal the random scalars used, leading again to the leakage of the undisclosed messages or the hidden signature. Therefore, implementations MUST apply proper side channel attack protection. One method to achieve this, is by using elliptic curve implementations that execute curve operations in constant time.</t>
</section>

<section anchor="presentation-header-selection"><name>Presentation Header Selection</name>
<t>The signature proofs of knowledge generated in this specification are created using a specified <tt>presentation_header</tt>. A Verifier-specified cryptographically random value (e.g., a nonce) featuring in the <tt>presentation_header</tt> provides strong protections against replay attacks, and is RECOMMENDED in most use cases. In some settings, proofs can be generated in a non-interactive fashion, in which case verifiers MUST be able to verify the uniqueness of the <tt>presentation_header</tt> values.</t>
</section>

<section anchor="implementing-hash-to-curve-g1"><name>Implementing hash_to_curve_g1</name>
<t>The security analysis models hash_to_curve_g1 as random oracles.  It is crucial that these functions are implemented using a cryptographically secure hash function.  For this purpose, implementations MUST meet the requirements of <xref target="RFC9380"/>.</t>
<t>In addition, ciphersuites MUST specify unique domain separation tags for hash_to_curve.  Some guidance around defining this can be found in <xref target="ciphersuites"/>.</t>
</section>

<section anchor="choice-of-underlying-curve"><name>Choice of Underlying Curve</name>
<t>BBS signatures can be implemented on any pairing-friendly curves suitable for type 3 pairing computations. However care must be taken when selecting one that is appropriate, to guarantee the desired security level for the targeted application. This specification defines a ciphersuite for using the BLS12-381 curve in <xref target="ciphersuites"/> which as a curve achieves around 117 bits of security <xref target="ZCASH-REVIEW"/>.</t>
</section>

<section anchor="randomness-requirements"><name>Randomness Requirements</name>
<t>The <tt>key_material</tt> input to the <tt>KeyGen</tt> operation defined in <xref target="secret-key"/> MUST be infeasible to guess and MUST be kept secret. One possibility is to generate the <tt>key_material</tt> from a trusted, cryptographically secure pseudo random function <xref target="RFC4086"/>. Secret keys MAY be generated using other methods; in this case they MUST be infeasible to guess and MUST be indistinguishable from uniformly random modulo r.</t>
<t>The <tt>ProofGen</tt> operation defined in <xref target="proof-generation-proofgen"/> is by its nature a randomized algorithm, requiring the generation of multiple uniformly distributed, pseudo random scalars. This makes <tt>ProofGen</tt> vulnerable to attacks caused by bad entropy (like the ones described in <xref target="HDWH12"/>). If randomness is re-used or is in any way predictable or maliciously constructed, an adversary may be able to unveil undisclosed information from the proof messages or the hidden signature value. More subtle attacks are also possible, where the security properties of the BBS proof may not be broken, but a system making use of the BBS scheme may still be compromised. As an example, consider systems that needs to monitor and potentially restrict outbound traffic, in order to minimize data leakage during a breach. In such cases, the attacker could manipulate couple of bits in the output of the <tt>get_random</tt> function (<xref target="parameters"/>) to create an undetected channel out of the system. Although the applicability of such attacks is limited for most of the targeted use cases of the BBS scheme, some applications may want to take measures towards mitigating them. To that end, it is RECOMMENDED to use a deterministic RNG (like a ChaCha20 based deterministic RNG), seeded with a unique, uniformly random, single seed <xref target="DRBG"/>. This will limit the amount of bits the attacker can manipulate (note that some randomness is always needed).</t>
<t>In any case, the randomness used in ProofGen MUST be unique in each call and MUST have a distribution that is indistinguishable from uniform. If the random scalars are re-used, created from "bad randomness" (for example with a known relationship to each other) or are in any way predictable, the undisclosed messages or the signature value may be compromised. Naturally, a cryptographically secure pseudorandom number generator or pseudo random function is REQUIRED to implement the <tt>get_random</tt> functionality. See <xref target="RFC4086"/> for guidance on implementing such functionality. See also <xref target="RFC8937"/>, for recommendations on generating good randomness in cases where the Prover has direct or in-direct access to a secret key.</t>
</section>

<section anchor="mapping-messages-to-scalars"><name>Mapping Messages to Scalars</name>
<t>In an application using BBS Signatures, there are two places where messages could be processed. First, before the messages are passed to the BBS Interface operations, and second, after they are passed to the BBS Interface operations but before they are passed to the BBS Core operations.</t>
<t>To allow for re-usability of software, it is RECOMMENDED that application specific processing (like UTF-8 encoding <xref target="RFC3629"/> or Base-64  decoding <xref target="RFC4648"/>) would happen before messages are passed to the BBS Interface operations. In those cases, the application should ensure that all protocol participants have a clear and consistent understanding of which method should be used to process a message. This can be achieved by associating specific Interfaces (with unique <tt>api_id</tt> values, see <xref target="defining-new-interfaces"/>) or unique <tt>header</tt> values (see <xref target="signature-generation-sign"/>) with different pre-processing methodologies.</t>
<t>Note that the BBS Interface defined in this document (see <xref target="bbs-signatures-interface"/>) only accepts messages that are represented as octet strings. However, in some more advanced applications, like the ones using range proofs (<xref target="BBB17"/>) to prove that a signed message is within some range (without disclosing that message), the pre-processing of messages may result to some of them being mapped to scalar values, before they are passed to the BBS Interface (for example, an application could use <xref target="ISO8601"/> to represent dates as integers or map the user's age directly to a number) that should directly be signed (e.g., to not be further processed by <tt>hash_to_scalar</tt>).</t>
<t>If a BBS Interface accepts both octet strings and scalar values as messages, where depending on the message's type different operations will be used to map it to a scalar (e.g., <tt>hash_to_scalar</tt> for octet strings and the identity operation for scalars), it must still ensure that the properties described in <xref target="define-a-new-map-to-scalar"/> holds. To that end, the application MUST ensure that it is clear to all participants, which message should be considered an octet string and which a scalar.</t>
<t>As an example, if the type (i.e., octet string or scalar) of the messages inputted to the BBS Interface, is uniquely determined by its index in the messages list (for example, first message is an octet string, second message a scalar etc.,), the map between message index and message type (determined by the Signer), could be made available as part of the Signer's public parameters (similar to <xref target="UPROVE"/>). This map would then be passed to the BBS Interface, which will use it to correctly map each message to a scalar. Another option, is to sign such configurations as part of the <tt>header</tt> parameter of the BBS signature (see <xref target="signature-generation-sign"/>). In this case, the map does not need to be published by the Signer.</t>
<t>If the application defines that the first (or last) <tt>n</tt> messages will be scalars and everything else octet strings, it could just publish the <tt>n</tt> value as part of the Signer's public parameters or again sign it as part of the <tt>header</tt> value.</t>
<t>In any case, the privacy considerations described in <xref target="privacy-considerations"/> MUST NOT be violated, for example, by using unique pre-processing rules or maps between message index and type. To validate the consistency of the message processing rules, the Prover could use mechanisms like the ones described in <xref target="I-D.ietf-privacypass-key-consistency"/>.</t>
</section>

<section anchor="post-quantum-security"><name>Post-quantum Security</name>
<t>BBS Signatures combine two security properties; data authenticity and data confidentiality.</t>
<t>Data authenticity refers to the inability of anyone other that the Signer being able to generate BBS signatures that are valid under the Signer's public key (this property is often referred to as unforgeability, or in the case of BBS Signatures, strong unforgeability, e.g., by <xref target="TZ23"/>). It also means that no one should be able to generate valid BBS proofs disclosing sets of messages, without first obtaining a valid BBS signature on those messages (in academic works, this is referred to as the BBS proof being a proof-of-knowledge of a BBS signature <xref target="CDL16"/> <xref target="TZ23"/>).</t>
<t>Data confidentiality means that no one (not even the Signer) should be able to use a BBS proof to extract information about the messages the Prover decided not to disclose during the proof generation process, or the signature that was used to generate that proof (something that is referred to as the zero-knowledge property of the BBS proof <xref target="BBDT16"/> <xref target="CDL16"/> <xref target="TZ23"/>).</t>
<t>On the presence of a Cryptographically Relevant Quantum Computer (CRQC), meaning a computer that will be able to break the discrete logarithm problem in the groups used by BBS Signatures (see <xref target="I-D.ietf-pquip-pqc-engineers"/>), the data authenticity property will not hold. Specifically, an adversary could use a CRQC to reveal the Signer's secret key from their public key, hence giving them the ability to generate BBS signatures on behalf of that Signer, for messages of their choosing, as well as BBS proofs using those signatures.</t>
<t>On the other hand, data confidentiality cannot be broken, even by adversaries with unbounded computational resources and in possession of the Signer's secret key. This means that even by utilizing a CRQC, adversaries will not be able to compromise the data confidentiality property of BBS proofs. As a result, an adversary with access to such a quantum computer, will not be able to reveal either the messages undisclosed by a BBS proof, or the hidden signature value (which the Prover showcases possession of). This guarantees that the privacy and hiding properties of BBS proofs that are currently used, will not be compromised by future quantum-attacks (a property that is often referred to as everlasting privacy). Note that this only considers BBS proofs, not BBS signatures, which do not possess the same hiding properties as the BBS proofs.</t>
</section>
</section>

<section anchor="ciphersuites"><name>Ciphersuites</name>
<t>This section defines the format for a BBS ciphersuite. It also gives concrete ciphersuites based on the BLS12-381 pairing-friendly elliptic curve <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/>.</t>

<section anchor="ciphersuite-format"><name>Ciphersuite Format</name>

<section anchor="ciphersuite-id"><name>Ciphersuite ID</name>
<t>The following section defines the format of the unique identifier for the ciphersuite denoted <tt>ciphersuite_id</tt>, which will be represented as an ASCII encoded octet string. The REQUIRED format for this string is</t>

<artwork><![CDATA[  "BBS_" || H2C_SUITE_ID || ADD_INFO
]]>
</artwork>

<ul>
<li><t>H2C_SUITE_ID is the suite ID of the hash-to-curve suite used to define the hash_to_curve function.</t>
</li>
<li><t>ADD_INFO is an optional octet string indicating any additional information used to uniquely qualify the ciphersuite. When present this value MUST only contain ASCII encoded characters with codes between 0x21 and 0x7e (inclusive) and MUST end with an underscore (ASCII code: 0x5f). The last character MUST be the only underscore.</t>
</li>
</ul>
</section>

<section anchor="additional-parameters"><name>Additional Parameters</name>
<t>The parameters that each ciphersuite needs to define are generally divided into three main categories; the basic parameters (a hash function, a pairing operation, the octet length of points and scalars, the hash to curve <xref target="RFC9380"/> related operations and parameters as well as the base point of the G1 subgroup), the serialization operations (mapping points from each elliptic curve to an octet string and vice versa) and the generator parameters. See below for more details.</t>
<t><strong>Basic parameters</strong>:</t>

<ul>
<li><t>hash: a cryptographic hash function.</t>
</li>
<li><t>octet_scalar_length: Number of bytes to represent a scalar value, in the multiplicative group of integers mod r, encoded as an octet string. It is RECOMMENDED this value be set to <tt>ceil(log2(r)/8)</tt>.</t>
</li>
<li><t>octet_point_length: Number of bytes to represent a point encoded as an octet string outputted by the <tt>point_to_octets_E*</tt> function.</t>
</li>
<li><t>hash_to_curve_suite: The hash-to-curve ciphersuite id, in the form defined in <xref target="RFC9380"/>. This defines the hash_to_curve_g1 (the hash_to_curve operation for the G1 subgroup, see the Notation defined in <xref target="notation"/>) and the expand_message (either expand_message_xmd or expand_message_xof) operations used in this document.</t>
</li>
<li><t>expand_len: Must be defined to be at least <tt>ceil((ceil(log2(r))+k)/8)</tt>, where <tt>log2(r)</tt> and <tt>k</tt> are defined by each ciphersuite (see Section 5 in <xref target="RFC9380"/> for a more detailed explanation of this definition).</t>
</li>
<li><t>P1: A fixed point in the G1 subgroup, different from the point BP1 (i.e., the base point of G1, see <xref target="terminology"/>). This leaves the base point "free", to be used with other protocols, like key commitment and proof of possession schemes (for example, like the one described in Section 3.3 of <xref target="I-D.irtf-cfrg-bls-signature"/>).</t>
</li>
<li><t>h: The pairing operation used.</t>
</li>
</ul>
<t><strong>Serialization functions</strong>:</t>

<ul>
<li><t>point_to_octets_E1:
a function that returns the canonical representation of the point P of the E1 elliptic curve as an octet string.</t>
</li>
<li><t>point_to_octets_E2:
a function that returns the canonical representation of the point P of the E2 elliptic curve as an octet string.</t>
</li>
<li><t>octets_to_point_E1:
a function that returns the point P in the elliptic curve E1 corresponding to the canonical representation ostr, or INVALID if ostr is not a valid output of <tt>point_to_octets_E1</tt>.</t>
</li>
<li><t>octets_to_point_E2:
a function that returns the point P in the elliptic curve E2 corresponding to the canonical representation ostr, or INVALID if ostr is not a valid output of <tt>point_to_octets_E2</tt>.</t>
</li>
</ul>
</section>
</section>

<section anchor="bls12-381-ciphersuites"><name>BLS12-381 Ciphersuites</name>
<t>The following two ciphersuites are based on the BLS12-381 elliptic curves defined in Section 4.2.1 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/>. The targeted security level of both suites in bits is <tt>k = 128</tt> (the actual security level is closer to 126 bits). The number of bits of the order <tt>r</tt>, of the G1 and G2 subgroups, is <tt>log2(r) = 255</tt>. The base points <tt>BP1</tt> and <tt>BP2</tt> of G1 and G2 are the points <tt>BP</tt> and <tt>BP'</tt> correspondingly, as defined in Section 4.2.1 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/>. For completeness, BLS12-381 and the relevant functionality (base points <tt>BP1</tt> and <tt>BP2</tt>, the pairing <tt>h</tt> as well as the point encoding and decoding operations) are defined in <xref target="the-bls12-381-curve"/>.</t>
<t>The first ciphersuite uses the hash-to-curve suite <tt>BLS12381G1_XOF:SHAKE-256_SSWU_RO_</tt>, defined by this document in <eref target="#bls12-381-hash_to_curve-def">Appendix A.1</eref>, which is based on the SHAKE-256 extendable output function, as defined in Section 6.2 of <xref target="SHA3"/>.</t>
<t>The second ciphersuite uses the hash-to-curve suite <tt>BLS12381G1_XMD:SHA-256_SSWU_RO_</tt>, defined in Section 8.8.1 of the <xref target="RFC9380"/> document, which is based on the SHA-256, as defined in Section 6.2 of <xref target="SHA2"/> .</t>
<t>For both ciphersuites defined in this section, the fixed point <tt>P1</tt> of G1 is defined as the output of the <tt>create_generators</tt> procedure defined in <xref target="generators-calculation"/> instantiated with the parameters defined by each ciphersuite, with the inputs <tt>count = 1</tt>, not supplying an <tt>api_id</tt> value and making use of the following "Definitions" for the <tt>seed_dst</tt>, <tt>generator_dst</tt> and <tt>generator_seed</tt> variables;</t>

<artwork><![CDATA[- seed_dst: ciphersuite_id || "H2G_HM2S_SIG_GENERATOR_SEED_" where
            "H2G_HM2S_SIG_GENERATOR_SEED_" is an ASCII string comprised
            of 28 bytes.
- generator_dst: ciphersuite_id || "H2G_HM2S_SIG_GENERATOR_DST_", where
                 "H2G_HM2S_SIG_GENERATOR_DST_" is an ASCII string
                 comprised of 27 bytes.
- generator_seed: ciphersuite_id || "H2G_HM2S_BP_MESSAGE_GENERATOR_SEED"
                  where "H2G_HM2S_BP_MESSAGE_GENERATOR_SEED" is an ASCII
                  string comprised of 34 bytes.
]]>
</artwork>
<t>In the above, <tt>ciphersuite_id</tt> is the unique identifier defined by each ciphersuite. Note that the <tt>P1</tt> point is independent from the BBS Interface that may use it and it remains constant for each ciphersuite. The similarity of the above "Definitions" with the Interface identifier (<tt>api_id</tt>) defined in <xref target="bbs-signatures-interface"/>, is only for compatibility reasons with previous versions of this document.</t>
<t>Note that these two ciphersuites differ only in the hash-to-curve suites used. The hash-to-curve suites differ in the <tt>expand_message</tt> variant and underlying hash function. More concretely, the <eref target="#bls12-381-shake-256">BLS12-381-SHAKE-256</eref> ciphersuite makes use of <tt>expand_message_xof</tt> with SHAKE-256, while <eref target="#bls12-381-sha-256">BLS12-381-SHA-256</eref> makes use of <tt>expand_message_xmd</tt> with SHA-256. Curve parameters are common between the two ciphersuites.</t>

<section anchor="bls12-381-shake-256"><name>BLS12-381-SHAKE-256</name>
<t><strong>Basic parameters</strong>:</t>

<ul>
<li><t>ciphersuite_id: "BBS_BLS12381G1_XOF:SHAKE-256_SSWU_RO_"</t>
</li>
<li><t>octet_scalar_length: 32, based on the RECOMMENDED approach of <tt>ceil(log2(r)/8)</tt>.</t>
</li>
<li><t>octet_point_length: 48, based on the RECOMMENDED approach of <tt>ceil(log2(p)/8)</tt>.</t>
</li>
<li><t>hash_to_curve_suite: "BLS12381G1_XOF:SHAKE-256_SSWU_RO_" as defined in <eref target="#bls12-381-hash-to-curve-definition-using-shake-256">Appendix A.1</eref> for the G1 subgroup.</t>
</li>
<li><t>expand_len: 48 ( <tt>= ceil((ceil(log2(r))+k)/8)</tt>)</t>
</li>
<li><t>P1: the following point of G1, serialized using the point_to_octets_E1 procedure defined by this ciphersuite and hex encoded</t>

<artwork><![CDATA[P1 = h'{{ $generatorFixtures.bls12-381-shake-256.generators.P1 }}'
]]>
</artwork>
</li>
<li><t>h: the optimal Ate pairing (Appendix A.2 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/>), defined in <xref target="optimal-ate-pairing"/>.</t>
</li>
</ul>
<t><strong>Serialization functions</strong>:</t>

<ul>
<li><t>point_to_octets_E1: as defined in <xref target="point-serialization"/> for points of the curve <tt>E1</tt> (which follows the format documented in Appendix C.1 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/> for the <tt>E1</tt> elliptic curve, using compression).</t>
</li>
<li><t>point_to_octets_E2: as defined in <xref target="point-serialization"/> for points of the curve <tt>E2</tt> (which follows the format documented in Appendix C.1 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/> for the <tt>E2</tt> elliptic curve, using compression).</t>
</li>
<li><t>octets_to_point_E1: as defined in <xref target="point-de-serialization"/> (which follows the format documented in Appendix C.2 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/>), returning INVALID if the resulting point is not in <tt>E1</tt>.</t>
</li>
<li><t>octets_to_point_E2: as defined in <xref target="point-de-serialization"/> (which follows the format documented in Appendix C.2 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/>), returning INVALID if the resulting point is not in <tt>E2</tt>.</t>
</li>
</ul>
</section>

<section anchor="bls12-381-sha-256"><name>BLS12-381-SHA-256</name>
<t><strong>Basic parameters</strong>:</t>

<ul>
<li><t>Ciphersuite_ID: "BBS_BLS12381G1_XMD:SHA-256_SSWU_RO_"</t>
</li>
<li><t>octet_scalar_length: 32, based on the RECOMMENDED approach of <tt>ceil(log2(r)/8)</tt>.</t>
</li>
<li><t>octet_point_length: 48, based on the RECOMMENDED approach of <tt>ceil(log2(p)/8)</tt>.</t>
</li>
<li><t>hash_to_curve_suite: "BLS12381G1_XMD:SHA-256_SSWU_RO_" as defined in Section 8.8.1 of the <xref target="RFC9380"/> for the G1 subgroup.</t>
</li>
<li><t>expand_len: 48 ( <tt>= ceil((ceil(log2(r))+k)/8)</tt>)</t>
</li>
<li><t>P1: the following point of G1, serialized using the point_to_octets_E1 procedure defined by this ciphersuite and hex encoded</t>

<artwork><![CDATA[P1 = h'{{ $generatorFixtures.bls12-381-sha-256.generators.P1 }}'
]]>
</artwork>
</li>
<li><t>h: the optimal Ate pairing (Appendix A.2 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/>), defined in <xref target="optimal-ate-pairing"/>.</t>
</li>
</ul>
<t><strong>Serialization functions</strong>:</t>

<ul>
<li><t>point_to_octets_E1: as defined in <xref target="point-serialization"/> for points of the curve <tt>E1</tt> (which follows the format documented in Appendix C.1 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/> for the <tt>E1</tt> elliptic curve, using compression).</t>
</li>
<li><t>point_to_octets_E2: as defined in <xref target="point-serialization"/> for points of the curve <tt>E2</tt> (which follows the format documented in Appendix C.1 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/> for the <tt>E2</tt> elliptic curve, using compression).</t>
</li>
<li><t>octets_to_point_E1: as defined in <xref target="point-de-serialization"/> (which follows the format documented in Appendix C.2 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/>), returning INVALID if the resulting point is not in <tt>E1</tt>.</t>
</li>
<li><t>octets_to_point_E2: as defined in <xref target="point-de-serialization"/> (which follows the format documented in Appendix C.2 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/>), returning INVALID if the resulting point is not in <tt>E2</tt>.</t>
</li>
</ul>
</section>
</section>
</section>

<section anchor="test-vectors"><name>Test Vectors</name>
<t>The following section details a basic set of test vectors that can be used to confirm an implementation's correctness.</t>
<t><strong>NOTE</strong> All binary data below is represented as octet strings in big endian order, encoded in hexadecimal format.</t>
<t><strong>NOTE</strong> These fixtures are a work in progress and subject to change.</t>

<section anchor="mocked-random-scalars"><name>Mocked Random Scalars</name>
<t>For the purpose of presenting fixtures for the <tt>ProofGen</tt> operation (<xref target="proof-generation-proofgen"/>), we describe here a way to mock the <tt>calculate_random_scalars</tt> operation (<xref target="random-scalars"/>), used by <tt>CoreProofGen</tt> (<xref target="coreproofgen"/>) to create all the necessary random scalars.</t>
<t>To that end, the <tt>seeded_random_scalars</tt> operation is defined, which will deterministically calculate <tt>count</tt> random-looking scalars from a single <tt>SEED</tt>, given a domain separation tag (<tt>DST</tt>). The proof test vector will then define a <tt>SEED</tt> (as a nothing-up-my-sleeve value) and a <tt>DST</tt> and then set</t>

<artwork><![CDATA[mocked_calculate_random_scalars(count) :=
                             seeded_random_scalars(SEED, DST, count)
]]>
</artwork>
<t>The <tt>mocked_calculate_random_scalars</tt> operation will be used in place of <tt>calculate_random_scalars</tt> during the <tt>CoreProofGen</tt> operation.</t>
<t><strong>Note</strong> For the <tt>BLS12-381-SHA-256</tt> ciphersuite (<xref target="bls12-381-sha-256"/>), if more than 170 mocked random scalars are required, the operation will return INVALID. Similarly, for the <tt>BLS12-381-SHAKE-256</tt> ciphersuite (<xref target="bls12-381-shake-256"/>), if more than 1365 mocked random scalars are required, the operation will return INVALID. For the purpose of describing <tt>ProofGen</tt> (<xref target="proof-generation-proofgen"/>) test vectors, those limits are inconsequential.</t>

<artwork><![CDATA[seeded_scalars = seeded_random_scalars(SEED, DST, count)

Inputs:

- SEED (REQUIRED), an octet string. The random seed from which to
                   generate the scalars.
- DST (REQUIRED), octet string representing a domain separation tag.
- count (REQUIRED), non negative integer. The number of scalars to
                    return.

Parameters:

- expand_message, the expand_message operation defined by the
                  ciphersuite.
- expand_len, defined by the ciphersuite.

Outputs:

- mocked_random_scalars, a list of "count" pseudo random scalars

ABORT if:

1. count * expand_len > 65535

Procedure:

1. out_len = expand_len * count
2. v = expand_message(SEED, DST, out_len)
3. if v is INVALID, return INVALID

4. for i in (1, ..., count):
5.     start_idx = (i-1) * expand_len
6.     end_idx = i * expand_len - 1
7.     r_i = OS2IP(v[start_idx..end_idx]) mod r
8. return (r_1, ...., r_count)
]]>
</artwork>
</section>

<section anchor="messages-1"><name>Messages</name>
<t>The following messages are used by the test vectors of both ciphersuites (unless otherwise stated). All the listed messages represent hex-encoded octet strings.</t>

<artwork><![CDATA[m_1 = h'{{ $messages[0] }}'
m_2 = h'{{ $messages[1] }}'
m_3 = h'{{ $messages[2] }}'
m_4 = h'{{ $messages[3] }}'
m_5 = h'{{ $messages[4] }}'
m_6 = h'{{ $messages[5] }}'
m_7 = h'{{ $messages[6] }}'
m_8 = h'{{ $messages[7] }}'
m_9 = h'{{ $messages[8] }}'
m_10 = h'{{ $messages[9] }}'
]]>
</artwork>
</section>

<section anchor="bls12-381-shake-256-test-vectors"><name>BLS12-381-SHAKE-256 Test Vectors</name>
<t>Test vectors of the <tt>BLS12-381-SHAKE-256</tt> ciphersuite defined in <xref target="bls12-381-shake-256-ciphersuite"/> ciphersuite. Further fixtures are available in <xref target="bls12-381-shake-256-ciphersuite"/>.</t>

<section anchor="key-pair"><name>Key Pair</name>
<t>Following the procedure defined in <xref target="secret-key"/> with an input <tt>key_material</tt> value as follows</t>

<artwork><![CDATA[key_material = h'{{ $KeyPairFixtures.bls12-381-shake-256.keypair.keyMaterial }}'
]]>
</artwork>
<t>the following <tt>key_info</tt> value</t>

<artwork><![CDATA[key_info = h'{{ $KeyPairFixtures.bls12-381-shake-256.keypair.keyInfo }}'
]]>
</artwork>
<t>and the following <tt>key_dst</tt> value, defined by <tt>api_id || KEYGEN_DST_</tt>, where <tt>api_id</tt> the identifier of the BBS Interface defined in <xref target="bbs-signatures-interface"/>, using the <tt>BLS12-381-SHAKE-256</tt> ciphersuite defined in <xref target="bls12-381-shake-256"/>, meaning that <tt>api_id = BBS_BLS12381G1_XOF:SHAKE-256_SSWU_RO_H2G_HM2S_</tt>,</t>

<artwork><![CDATA[key_dst = h'{{ $KeyPairFixtures.bls12-381-shake-256.keypair.keyDst }}'
]]>
</artwork>
<t>Outputs the following SK value</t>

<artwork><![CDATA[SK = 0x'{{ $KeyPairFixtures.bls12-381-shake-256.keypair.keyPair.secretKey }}'
]]>
</artwork>
<t>Following the procedure defined in <xref target="public-key"/> with an input SK value as above produces the following PK value</t>

<artwork><![CDATA[PK = h'{{ $KeyPairFixtures.bls12-381-shake-256.keypair.keyPair.publicKey }}'
]]>
</artwork>
</section>

<section anchor="map-messages-to-scalars"><name>Map Messages to Scalars</name>
<t>The messages in <xref target="messages-1"/> are mapped to scalars during the Sign, Verify, ProofGen and ProofVerify operations. Presented below, are the output scalar values of the messages_to_scalars operation (<xref target="messages-to-scalars"/>), on input the messages defined in <xref target="messages-1"/> and the <tt>api_id</tt> defined in <xref target="bbs-signatures-interface"/>, using the <tt>BLS12-381-SHAKE-256</tt> ciphersuite defined in <xref target="bls12-381-shake-256"/>, meaning that <tt>api_id = BBS_BLS12381G1_XOF:SHAKE-256_SSWU_RO_H2G_HM2S_</tt>. Each output scalar value is encoded to octets using I2OSP and represented in big endian order,</t>

<artwork><![CDATA[msg_scalar_1 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-shake-256.MapMessageToScalarAsHash.cases[0].scalar }}'
msg_scalar_2 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-shake-256.MapMessageToScalarAsHash.cases[1].scalar }}'
msg_scalar_3 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-shake-256.MapMessageToScalarAsHash.cases[2].scalar }}'
msg_scalar_4 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-shake-256.MapMessageToScalarAsHash.cases[3].scalar }}'
msg_scalar_5 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-shake-256.MapMessageToScalarAsHash.cases[4].scalar }}'
msg_scalar_6 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-shake-256.MapMessageToScalarAsHash.cases[5].scalar }}'
msg_scalar_7 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-shake-256.MapMessageToScalarAsHash.cases[6].scalar }}'
msg_scalar_8 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-shake-256.MapMessageToScalarAsHash.cases[7].scalar }}'
msg_scalar_9 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-shake-256.MapMessageToScalarAsHash.cases[8].scalar }}'
msg_scalar_10 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-shake-256.MapMessageToScalarAsHash.cases[9].scalar }}'
]]>
</artwork>
</section>

<section anchor="message-generators"><name>Message Generators</name>
<t>Following the procedure defined in <xref target="generators-calculation"/> for the <eref target="#bls12-381-shake-256">BLS12-381-SHAKE-256</eref> suite, with an input count value of 11 and an <tt>api_id</tt> value of <tt>api_id = BBS_BLS12381G1_XOF:SHAKE-256_SSWU_RO_H2G_HM2S_</tt> (as defined in <xref target="bbs-signatures-interface"/> for the <tt>BLS12-381-SHAKE-256</tt> ciphersuite), outputs the following values (note that the first one corresponds to <tt>Q_1</tt>, while the next 10, to the message generators <tt>H_1, ..., H_10</tt>).</t>

<artwork><![CDATA[Q_1 = h'{{ $generatorFixtures.bls12-381-shake-256.generators.Q1 }}'
H_1 = h'{{ $generatorFixtures.bls12-381-shake-256.generators.MsgGenerators[0] }}'
H_2 = h'{{ $generatorFixtures.bls12-381-shake-256.generators.MsgGenerators[1] }}'
H_3 = h'{{ $generatorFixtures.bls12-381-shake-256.generators.MsgGenerators[2] }}'
H_4 = h'{{ $generatorFixtures.bls12-381-shake-256.generators.MsgGenerators[3] }}'
H_5 = h'{{ $generatorFixtures.bls12-381-shake-256.generators.MsgGenerators[4] }}'
H_6 = h'{{ $generatorFixtures.bls12-381-shake-256.generators.MsgGenerators[5] }}'
H_7 = h'{{ $generatorFixtures.bls12-381-shake-256.generators.MsgGenerators[6] }}'
H_8 = h'{{ $generatorFixtures.bls12-381-shake-256.generators.MsgGenerators[7] }}'
H_9 = h'{{ $generatorFixtures.bls12-381-shake-256.generators.MsgGenerators[8] }}'
H_10 = h'{{ $generatorFixtures.bls12-381-shake-256.generators.MsgGenerators[9] }}'
]]>
</artwork>
</section>

<section anchor="signature-fixtures"><name>Signature Fixtures</name>
<t>This section presents test vectors for the <tt>Sign</tt> operation, as defined in <xref target="signature-generation-sign"/>, for the <tt>BLS12-381-SHAKE-256</tt> ciphersuite (<xref target="bls12-381-shake-256"/>).</t>

<section anchor="valid-single-message-signature"><name>Valid Single Message Signature</name>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-shake-256.signature001.messages[0] }}'

SK = 0x'{{ $signatureFixtures.bls12-381-shake-256.signature001.signerKeyPair.secretKey }}'
PK = h'{{ $signatureFixtures.bls12-381-shake-256.signature001.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-shake-256.signature001.header }}'

B = h'{{ $signatureFixtures.bls12-381-shake-256.signature001.trace.B }}'
domain = 0x'{{ $signatureFixtures.bls12-381-shake-256.signature001.trace.domain }}'

signature = h'{{ $signatureFixtures.bls12-381-shake-256.signature001.signature }}'
]]>
</artwork>
</section>

<section anchor="valid-multi-message-signature"><name>Valid Multi-Message Signature</name>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-shake-256.signature004.messages[0] }}'
m_2 = h'{{ $signatureFixtures.bls12-381-shake-256.signature004.messages[1] }}'
m_3 = h'{{ $signatureFixtures.bls12-381-shake-256.signature004.messages[2] }}'
m_4 = h'{{ $signatureFixtures.bls12-381-shake-256.signature004.messages[3] }}'
m_5 = h'{{ $signatureFixtures.bls12-381-shake-256.signature004.messages[4] }}'
m_6 = h'{{ $signatureFixtures.bls12-381-shake-256.signature004.messages[5] }}'
m_7 = h'{{ $signatureFixtures.bls12-381-shake-256.signature004.messages[6] }}'
m_8 = h'{{ $signatureFixtures.bls12-381-shake-256.signature004.messages[7] }}'
m_9 = h'{{ $signatureFixtures.bls12-381-shake-256.signature004.messages[8] }}'
m_10 = h'{{ $signatureFixtures.bls12-381-shake-256.signature004.messages[9] }}'

SK = 0x'{{ $signatureFixtures.bls12-381-shake-256.signature004.signerKeyPair.secretKey }}'
PK = h'{{ $signatureFixtures.bls12-381-shake-256.signature004.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-shake-256.signature004.header }}'

B = h'{{ $signatureFixtures.bls12-381-shake-256.signature004.trace.B }}'
domain = 0x'{{ $signatureFixtures.bls12-381-shake-256.signature004.trace.domain }}'

signature = h'{{ $signatureFixtures.bls12-381-shake-256.signature004.signature }}'
]]>
</artwork>
</section>
</section>

<section anchor="proof-fixtures"><name>Proof Fixtures</name>
<t>This section presents test vectors for the <tt>ProofGen</tt> operation, as defined in <xref target="proof-generation-proofgen"/>, for the <tt>BLS12-381-SHAKE-256</tt> ciphersuite (<xref target="bls12-381-shake-256"/>).</t>
<t>For the generation of the following test vectors, the <tt>mocked_calculate_random_scalars</tt> defined in <xref target="mocked-random-scalars"/> is used, in place of the <tt>calculate_random_scalars</tt> operation, with the following <tt>SEED</tt> value (hex encoding of the ASCII-encoded 30 first digits of pi)</t>

<artwork><![CDATA[SEED =
     h'332e313431353932363533353839373933323338343632363433333833323739'
]]>
</artwork>
<t>and the domain separation tag <tt>DST = api_id || "MOCK_RANDOM_SCALARS_DST_"</tt>, where <tt>api_id</tt> is the identifier of the BBS Interface defined in <xref target="bbs-signatures-interface"/>, i.e., <tt>api_id = ciphersuite_id || H2G_HM2S_</tt>, where <tt>ciphersuite_id</tt> is the unique identifier of the <tt>BLS12-381-SHAKE-256</tt> ciphersuite as defined in <xref target="bls12-381-shake-256"/> and <tt>"MOCK_RANDOM_SCALARS_DST_"</tt> is an ASCII string composed of 24 bytes. More specifically,</t>

<artwork><![CDATA[DST =
"BBS_BLS12381G1_XOF:SHAKE-256_SSWU_RO_H2G_HM2S_MOCK_RANDOM_SCALARS_DST_"
]]>
</artwork>
<t>Given the above <tt>SEED</tt> and <tt>DST</tt> values, the first 10 scalars (i.e., with <tt>count = 10</tt>) returned by the <tt>mocked_calculate_random_scalars</tt> operation will be,</t>

<artwork><![CDATA[random_scalar_1 = 0x'{{ $MockRngFixtures.bls12-381-shake-256.mockedRng.mockedScalars[0] }}'
random_scalar_2 = 0x'{{ $MockRngFixtures.bls12-381-shake-256.mockedRng.mockedScalars[1] }}'
random_scalar_3 = 0x'{{ $MockRngFixtures.bls12-381-shake-256.mockedRng.mockedScalars[2] }}'
random_scalar_4 = 0x'{{ $MockRngFixtures.bls12-381-shake-256.mockedRng.mockedScalars[3] }}'
random_scalar_5 = 0x'{{ $MockRngFixtures.bls12-381-shake-256.mockedRng.mockedScalars[4] }}'
random_scalar_6 = 0x'{{ $MockRngFixtures.bls12-381-shake-256.mockedRng.mockedScalars[5] }}'
random_scalar_7 = 0x'{{ $MockRngFixtures.bls12-381-shake-256.mockedRng.mockedScalars[6] }}'
random_scalar_8 = 0x'{{ $MockRngFixtures.bls12-381-shake-256.mockedRng.mockedScalars[7] }}'
random_scalar_9 = 0x'{{ $MockRngFixtures.bls12-381-shake-256.mockedRng.mockedScalars[8] }}'
random_scalar_10 = 0x'{{ $MockRngFixtures.bls12-381-shake-256.mockedRng.mockedScalars[9] }}'
]]>
</artwork>

<section anchor="valid-single-message-proof"><name>Valid Single Message Proof</name>

<artwork><![CDATA[m_0 = h'{{ $proofFixtures.bls12-381-shake-256.proof001.messages[0] }}'

public_key = h'{{ $proofFixtures.bls12-381-shake-256.proof001.signerPublicKey }}'
signature = h'{{ $proofFixtures.bls12-381-shake-256.proof001.signature }}'
header = h'{{ $proofFixtures.bls12-381-shake-256.proof001.header }}'
presentation_header = h'{{ $proofFixtures.bls12-381-shake-256.proof001.presentationHeader }}'
revealed_indexes = {{ $proofFixtures.bls12-381-shake-256.proof001.disclosedIndexes }}

random scalars:
    r1 = 0x'{{ $proofFixtures.bls12-381-shake-256.proof001.trace.random_scalars.r1 }}'
    r2 = 0x'{{ $proofFixtures.bls12-381-shake-256.proof001.trace.random_scalars.r2 }}'
    e_tilde = 0x'{{ $proofFixtures.bls12-381-shake-256.proof001.trace.random_scalars.e_tilde }}'
    r1_tilde = 0x'{{ $proofFixtures.bls12-381-shake-256.proof001.trace.random_scalars.r1_tilde }}'
    r3_tilde = 0x'{{ $proofFixtures.bls12-381-shake-256.proof001.trace.random_scalars.r3_tilde }}'
    m_tilde_scalars: {{ $proofFixtures.bls12-381-shake-256.proof001.trace.random_scalars.m_tilde_scalars }}

T1 = h'{{ $proofFixtures.bls12-381-shake-256.proof001.trace.T1 }}'
T2 = h'{{ $proofFixtures.bls12-381-shake-256.proof001.trace.T2 }}'
domain = 0x'{{ $proofFixtures.bls12-381-shake-256.proof001.trace.domain }}'

proof = h'{{ $proofFixtures.bls12-381-shake-256.proof001.proof }}'
]]>
</artwork>
</section>

<section anchor="valid-multi-message-all-messages-disclosed-proof"><name>Valid Multi-Message, All Messages Disclosed Proof</name>

<artwork><![CDATA[m_1 = h'{{ $proofFixtures.bls12-381-shake-256.proof002.messages[0] }}'
m_2 = h'{{ $proofFixtures.bls12-381-shake-256.proof002.messages[1] }}'
m_3 = h'{{ $proofFixtures.bls12-381-shake-256.proof002.messages[2] }}'
m_4 = h'{{ $proofFixtures.bls12-381-shake-256.proof002.messages[3] }}'
m_5 = h'{{ $proofFixtures.bls12-381-shake-256.proof002.messages[4] }}'
m_6 = h'{{ $proofFixtures.bls12-381-shake-256.proof002.messages[5] }}'
m_7 = h'{{ $proofFixtures.bls12-381-shake-256.proof002.messages[6] }}'
m_8 = h'{{ $proofFixtures.bls12-381-shake-256.proof002.messages[7] }}'
m_9 = h'{{ $proofFixtures.bls12-381-shake-256.proof002.messages[8] }}'
m_10 = h'{{ $proofFixtures.bls12-381-shake-256.proof002.messages[9] }}'

public_key = h'{{ $proofFixtures.bls12-381-shake-256.proof002.signerPublicKey }}'
signature = h'{{ $proofFixtures.bls12-381-shake-256.proof002.signature }}'
header = h'{{ $proofFixtures.bls12-381-shake-256.proof002.header }}'
presentation_header = h'{{ $proofFixtures.bls12-381-shake-256.proof002.presentationHeader }}'
revealed_indexes = {{ $proofFixtures.bls12-381-shake-256.proof002.disclosedIndexes }}

random scalars:
    r1 = 0x'{{ $proofFixtures.bls12-381-shake-256.proof002.trace.random_scalars.r1 }}'
    r2 = 0x'{{ $proofFixtures.bls12-381-shake-256.proof002.trace.random_scalars.r2 }}'
    e_tilde = 0x'{{ $proofFixtures.bls12-381-shake-256.proof002.trace.random_scalars.e_tilde }}'
    r1_tilde = 0x'{{ $proofFixtures.bls12-381-shake-256.proof002.trace.random_scalars.r1_tilde }}'
    r3_tilde = 0x'{{ $proofFixtures.bls12-381-shake-256.proof002.trace.random_scalars.r3_tilde }}'
    m_tilde_scalars: {{ $proofFixtures.bls12-381-shake-256.proof002.trace.random_scalars.m_tilde_scalars }}

T1 = h'{{ $proofFixtures.bls12-381-shake-256.proof002.trace.T1 }}'
T2 = h'{{ $proofFixtures.bls12-381-shake-256.proof002.trace.T2 }}'
domain = 0x'{{ $proofFixtures.bls12-381-shake-256.proof002.trace.domain }}'

proof = h'{{ $proofFixtures.bls12-381-shake-256.proof002.proof }}'
]]>
</artwork>
</section>

<section anchor="valid-multi-message-some-messages-disclosed-proof"><name>Valid Multi-Message, Some Messages Disclosed Proof</name>

<artwork><![CDATA[m_1 = h'{{ $proofFixtures.bls12-381-shake-256.proof003.messages[0] }}'
m_2 = h'{{ $proofFixtures.bls12-381-shake-256.proof003.messages[1] }}'
m_3 = h'{{ $proofFixtures.bls12-381-shake-256.proof003.messages[2] }}'
m_4 = h'{{ $proofFixtures.bls12-381-shake-256.proof003.messages[3] }}'
m_5 = h'{{ $proofFixtures.bls12-381-shake-256.proof003.messages[4] }}'
m_6 = h'{{ $proofFixtures.bls12-381-shake-256.proof003.messages[5] }}'
m_7 = h'{{ $proofFixtures.bls12-381-shake-256.proof003.messages[6] }}'
m_8 = h'{{ $proofFixtures.bls12-381-shake-256.proof003.messages[7] }}'
m_9 = h'{{ $proofFixtures.bls12-381-shake-256.proof003.messages[8] }}'
m_10 = h'{{ $proofFixtures.bls12-381-shake-256.proof003.messages[9] }}'

public_key = h'{{ $proofFixtures.bls12-381-shake-256.proof003.signerPublicKey }}'
signature = h'{{ $proofFixtures.bls12-381-shake-256.proof003.signature }}'
header = h'{{ $proofFixtures.bls12-381-shake-256.proof003.header }}'
presentation_header = h'{{ $proofFixtures.bls12-381-shake-256.proof003.presentationHeader }}'
revealed_indexes = {{ $proofFixtures.bls12-381-shake-256.proof003.disclosedIndexes }}

random scalars:
    r1 = 0x'{{ $proofFixtures.bls12-381-shake-256.proof003.trace.random_scalars.r1 }}'
    r2 = 0x'{{ $proofFixtures.bls12-381-shake-256.proof003.trace.random_scalars.r2 }}'
    e_tilde = 0x'{{ $proofFixtures.bls12-381-shake-256.proof003.trace.random_scalars.e_tilde }}'
    r1_tilde = 0x'{{ $proofFixtures.bls12-381-shake-256.proof003.trace.random_scalars.r1_tilde }}'
    r3_tilde = 0x'{{ $proofFixtures.bls12-381-shake-256.proof003.trace.random_scalars.r3_tilde }}'
    m_tilde_scalars:
        m~_1 = 0x'{{ $proofFixtures.bls12-381-shake-256.proof003.trace.random_scalars.m_tilde_scalars[0] }}'
        m~_3 = 0x'{{ $proofFixtures.bls12-381-shake-256.proof003.trace.random_scalars.m_tilde_scalars[1] }}'
        m~_5 = 0x'{{ $proofFixtures.bls12-381-shake-256.proof003.trace.random_scalars.m_tilde_scalars[2] }}'
        m~_7 = 0x'{{ $proofFixtures.bls12-381-shake-256.proof003.trace.random_scalars.m_tilde_scalars[3] }}'
        m~_8 = 0x'{{ $proofFixtures.bls12-381-shake-256.proof003.trace.random_scalars.m_tilde_scalars[4] }}'
        m~_9 = 0x'{{ $proofFixtures.bls12-381-shake-256.proof003.trace.random_scalars.m_tilde_scalars[5] }}'

T1 = h'{{ $proofFixtures.bls12-381-shake-256.proof003.trace.T1 }}'
T2 = h'{{ $proofFixtures.bls12-381-shake-256.proof003.trace.T2 }}'
domain = 0x'{{ $proofFixtures.bls12-381-shake-256.proof003.trace.domain }}'

proof = h'{{ $proofFixtures.bls12-381-shake-256.proof003.proof }}'
]]>
</artwork>
</section>
</section>
</section>

<section anchor="bls12381-sha-256-test-vectors"><name>BLS12381-SHA-256 Test Vectors</name>
<t>Test vectors of the <eref target="#bls12-381-sha-256-ciphersuite">BLS12-381-SHA-256</eref> ciphersuite. Further fixtures are available in <xref target="bls12-381-sha-256-ciphersuite"/>.</t>

<section anchor="key-pair-1"><name>Key Pair</name>
<t>Following the procedure defined in <xref target="secret-key"/> with an input <tt>key_material</tt> value as follows</t>

<artwork><![CDATA[key_material = h'{{ $KeyPairFixtures.bls12-381-sha-256.keypair.keyMaterial }}'
]]>
</artwork>
<t>the following <tt>key_info</tt> value</t>

<artwork><![CDATA[key_info = h'{{ $KeyPairFixtures.bls12-381-sha-256.keypair.keyInfo }}'
]]>
</artwork>
<t>and the following <tt>key_dst</tt> value, defined by <tt>api_id || KEYGEN_DST_</tt>, where <tt>api_id</tt> the identifier of the BBS Interface defined in <xref target="bbs-signatures-interface"/>, using the <tt>BLS12-381-SHA-256</tt> ciphersuite defined in <xref target="bls12-381-sha-256"/>, meaning that <tt>api_id = BBS_BLS12381G1_XMD:SHA-256_SSWU_RO_H2G_HM2S_</tt>,</t>

<artwork><![CDATA[key_dst = h'{{ $KeyPairFixtures.bls12-381-sha-256.keypair.keyDst }}'
]]>
</artwork>
<t>Outputs the following SK value</t>

<artwork><![CDATA[SK = 0x'{{ $KeyPairFixtures.bls12-381-sha-256.keypair.keyPair.secretKey }}'
]]>
</artwork>
<t>Following the procedure defined in <xref target="public-key"/> with an input SK value as above produces the following PK value</t>

<artwork><![CDATA[PK = h'{{ $KeyPairFixtures.bls12-381-sha-256.keypair.keyPair.publicKey }}'
]]>
</artwork>
</section>

<section anchor="map-messages-to-scalars-1"><name>Map Messages to Scalars</name>
<t>The messages in <xref target="messages-1"/> are mapped to scalars during the Sign, Verify, ProofGen and ProofVerify operations. Presented below, are the output scalar values of the messages_to_scalars operation (<xref target="messages-to-scalars"/>), on input the messages defined in <xref target="messages-1"/> and the <tt>api_id</tt> defined in <xref target="bbs-signatures-interface"/>, using the <tt>BLS12-381-SHA-256</tt> ciphersuite defined in <xref target="bls12-381-sha-256"/>, meaning that <tt>api_id = BBS_BLS12381G1_XMD:SHA-256_SSWU_RO_H2G_HM2S_</tt>. Each output scalar value is encoded to octets using I2OSP and represented in big endian order,</t>

<artwork><![CDATA[dst = h'{{ $MapMessageToScalarFixtures.bls12-381-sha-256.MapMessageToScalarAsHash.dst }}'
]]>
</artwork>
<t>The output scalars, encoded to octets using I2OSP and represented in big endian order, are the following,</t>

<artwork><![CDATA[msg_scalar_1 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-sha-256.MapMessageToScalarAsHash.cases[0].scalar }}'
msg_scalar_2 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-sha-256.MapMessageToScalarAsHash.cases[1].scalar }}'
msg_scalar_3 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-sha-256.MapMessageToScalarAsHash.cases[2].scalar }}'
msg_scalar_4 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-sha-256.MapMessageToScalarAsHash.cases[3].scalar }}'
msg_scalar_5 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-sha-256.MapMessageToScalarAsHash.cases[4].scalar }}'
msg_scalar_6 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-sha-256.MapMessageToScalarAsHash.cases[5].scalar }}'
msg_scalar_7 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-sha-256.MapMessageToScalarAsHash.cases[6].scalar }}'
msg_scalar_8 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-sha-256.MapMessageToScalarAsHash.cases[7].scalar }}'
msg_scalar_9 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-sha-256.MapMessageToScalarAsHash.cases[8].scalar }}'
msg_scalar_10 = 0x'{{ $MapMessageToScalarFixtures.bls12-381-sha-256.MapMessageToScalarAsHash.cases[9].scalar }}'
]]>
</artwork>
</section>

<section anchor="message-generators-1"><name>Message Generators</name>
<t>Following the procedure defined in <xref target="generators-calculation"/> for the <eref target="#bls12-381-sha-256">BLS12-381-SHA-256</eref> suite, with an input count value of 11 and an <tt>api_id</tt> value of <tt>api_id = BBS_BLS12381G1_XMD:SHA-256_SSWU_RO_H2G_HM2S_</tt> (as defined in <xref target="bbs-signatures-interface"/> for the <tt>BLS12-381-SHA-256</tt> ciphersuite), outputs the following values (note that the first one corresponds to <tt>Q_1</tt>, while the next 10, to the message generators <tt>H_1, ..., H_10</tt>).</t>

<artwork><![CDATA[Q_1 = h'{{ $generatorFixtures.bls12-381-sha-256.generators.Q1 }}'
H_1 = h'{{ $generatorFixtures.bls12-381-sha-256.generators.MsgGenerators[0] }}'
H_2 = h'{{ $generatorFixtures.bls12-381-sha-256.generators.MsgGenerators[1] }}'
H_3 = h'{{ $generatorFixtures.bls12-381-sha-256.generators.MsgGenerators[2] }}'
H_4 = h'{{ $generatorFixtures.bls12-381-sha-256.generators.MsgGenerators[3] }}'
H_5 = h'{{ $generatorFixtures.bls12-381-sha-256.generators.MsgGenerators[4] }}'
H_6 = h'{{ $generatorFixtures.bls12-381-sha-256.generators.MsgGenerators[5] }}'
H_7 = h'{{ $generatorFixtures.bls12-381-sha-256.generators.MsgGenerators[6] }}'
H_8 = h'{{ $generatorFixtures.bls12-381-sha-256.generators.MsgGenerators[7] }}'
H_9 = h'{{ $generatorFixtures.bls12-381-sha-256.generators.MsgGenerators[8] }}'
H_10 = h'{{ $generatorFixtures.bls12-381-sha-256.generators.MsgGenerators[9] }}'
]]>
</artwork>
</section>

<section anchor="signature-fixtures-1"><name>Signature Fixtures</name>
<t>This section presents test vectors for the <tt>Sign</tt> operation, as defined in <xref target="signature-generation-sign"/>, for the <tt>BLS12-381-SHA-256</tt> ciphersuite (<xref target="bls12-381-sha-256"/>).</t>

<section anchor="valid-single-message-signature-1"><name>Valid Single Message Signature</name>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-sha-256.signature001.messages[0] }}'

SK = 0x'{{ $signatureFixtures.bls12-381-sha-256.signature001.signerKeyPair.secretKey }}'
PK = h'{{ $signatureFixtures.bls12-381-sha-256.signature001.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-sha-256.signature001.header }}'

B = h'{{ $signatureFixtures.bls12-381-sha-256.signature001.trace.B }}'
domain = 0x'{{ $signatureFixtures.bls12-381-sha-256.signature001.trace.domain }}'

signature = h'{{ $signatureFixtures.bls12-381-sha-256.signature001.signature }}'
]]>
</artwork>
</section>

<section anchor="valid-multi-message-signature-1"><name>Valid Multi-Message Signature</name>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-sha-256.signature004.messages[0] }}'
m_2 = h'{{ $signatureFixtures.bls12-381-sha-256.signature004.messages[1] }}'
m_3 = h'{{ $signatureFixtures.bls12-381-sha-256.signature004.messages[2] }}'
m_4 = h'{{ $signatureFixtures.bls12-381-sha-256.signature004.messages[3] }}'
m_5 = h'{{ $signatureFixtures.bls12-381-sha-256.signature004.messages[4] }}'
m_6 = h'{{ $signatureFixtures.bls12-381-sha-256.signature004.messages[5] }}'
m_7 = h'{{ $signatureFixtures.bls12-381-sha-256.signature004.messages[6] }}'
m_8 = h'{{ $signatureFixtures.bls12-381-sha-256.signature004.messages[7] }}'
m_9 = h'{{ $signatureFixtures.bls12-381-sha-256.signature004.messages[8] }}'
m_10 = h'{{ $signatureFixtures.bls12-381-sha-256.signature004.messages[9] }}'

SK = 0x'{{ $signatureFixtures.bls12-381-sha-256.signature004.signerKeyPair.secretKey }}'
PK = h'{{ $signatureFixtures.bls12-381-sha-256.signature004.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-sha-256.signature004.header }}'

B = h'{{ $signatureFixtures.bls12-381-sha-256.signature004.trace.B }}'
domain = 0x'{{ $signatureFixtures.bls12-381-sha-256.signature004.trace.domain }}'

signature = h'{{ $signatureFixtures.bls12-381-sha-256.signature004.signature }}'
]]>
</artwork>
</section>
</section>

<section anchor="proof-fixtures-1"><name>Proof Fixtures</name>
<t>This section presents test vectors for the <tt>ProofGen</tt> operation, as defined in <xref target="proof-generation-proofgen"/>, for the <tt>BLS12-381-SHA-256</tt> ciphersuite (<xref target="bls12-381-shake-256"/>).</t>
<t>For the generation of the following test vectors, the <tt>mocked_calculate_random_scalars</tt> defined in <xref target="mocked-random-scalars"/> is used, in place of the <tt>calculate_random_scalars</tt> operation, with the following <tt>SEED</tt> value (hex encoding of the ASCII-encoded 30 first digits of pi)</t>

<artwork><![CDATA[SEED =
     h'332e313431353932363533353839373933323338343632363433333833323739'
]]>
</artwork>
<t>and the domain separation tag <tt>DST = api_id || "MOCK_RANDOM_SCALARS_DST_"</tt>, where <tt>api_id</tt> is the identifier of the BBS Interface defined in <xref target="bbs-signatures-interface"/>, i.e., <tt>api_id = ciphersuite_id || H2G_HM2S_</tt>, where <tt>ciphersuite_id</tt> is the unique identifier of the <tt>BLS12-381-SHA-256</tt> ciphersuite as defined in <xref target="bls12-381-sha-256"/> and <tt>"MOCK_RANDOM_SCALARS_DST_"</tt> is an ASCII string composed of 24 bytes. More specifically,</t>

<artwork><![CDATA[DST =
  "BBS_BLS12381G1_XMD:SHA-256_SSWU_RO_H2G_HM2S_MOCK_RANDOM_SCALARS_DST_"
]]>
</artwork>
<t>Given the above <tt>SEED</tt> and <tt>DST</tt> values, the first 10 scalars (i.e., with <tt>count = 10</tt>) returned by the <tt>mocked_calculate_random_scalars</tt> operation will be,</t>

<artwork><![CDATA[random_scalar_1 = 0x'{{ $MockRngFixtures.bls12-381-sha-256.mockedRng.mockedScalars[0] }}'
random_scalar_2 = 0x'{{ $MockRngFixtures.bls12-381-sha-256.mockedRng.mockedScalars[1] }}'
random_scalar_3 = 0x'{{ $MockRngFixtures.bls12-381-sha-256.mockedRng.mockedScalars[2] }}'
random_scalar_4 = 0x'{{ $MockRngFixtures.bls12-381-sha-256.mockedRng.mockedScalars[3] }}'
random_scalar_5 = 0x'{{ $MockRngFixtures.bls12-381-sha-256.mockedRng.mockedScalars[4] }}'
random_scalar_6 = 0x'{{ $MockRngFixtures.bls12-381-sha-256.mockedRng.mockedScalars[5] }}'
random_scalar_7 = 0x'{{ $MockRngFixtures.bls12-381-sha-256.mockedRng.mockedScalars[6] }}'
random_scalar_8 = 0x'{{ $MockRngFixtures.bls12-381-sha-256.mockedRng.mockedScalars[7] }}'
random_scalar_9 = 0x'{{ $MockRngFixtures.bls12-381-sha-256.mockedRng.mockedScalars[8] }}'
random_scalar_10 = 0x'{{ $MockRngFixtures.bls12-381-sha-256.mockedRng.mockedScalars[9] }}'
]]>
</artwork>
<t>Note that the returned scalars will be unique for different <tt>count</tt> values, i.e., for different output lengths.</t>

<section anchor="valid-single-message-proof-1"><name>Valid Single Message Proof</name>

<artwork><![CDATA[m_0 = h'{{ $proofFixtures.bls12-381-sha-256.proof001.messages[0] }}'

public_key = h'{{ $proofFixtures.bls12-381-sha-256.proof001.signerPublicKey }}'
signature = h'{{ $proofFixtures.bls12-381-sha-256.proof001.signature }}'
header = h'{{ $proofFixtures.bls12-381-sha-256.proof001.header }}'
presentation_header = h'{{ $proofFixtures.bls12-381-sha-256.proof001.presentationHeader }}'
revealed_indexes = {{ $proofFixtures.bls12-381-sha-256.proof001.disclosedIndexes }}

random scalars:
    r1 = 0x'{{ $proofFixtures.bls12-381-sha-256.proof001.trace.random_scalars.r1 }}'
    r2 = 0x'{{ $proofFixtures.bls12-381-sha-256.proof001.trace.random_scalars.r2 }}'
    e_tilde = 0x'{{ $proofFixtures.bls12-381-sha-256.proof001.trace.random_scalars.e_tilde }}'
    r1_tilde = 0x'{{ $proofFixtures.bls12-381-sha-256.proof001.trace.random_scalars.r1_tilde }}'
    r3_tilde = 0x'{{ $proofFixtures.bls12-381-sha-256.proof001.trace.random_scalars.r3_tilde }}'
    m_tilde_scalars: {{ $proofFixtures.bls12-381-sha-256.proof001.trace.random_scalars.m_tilde_scalars }}

T1 = h'{{ $proofFixtures.bls12-381-sha-256.proof001.trace.T1 }}'
T2 = h'{{ $proofFixtures.bls12-381-sha-256.proof001.trace.T2 }}'
domain = 0x'{{ $proofFixtures.bls12-381-sha-256.proof001.trace.domain }}'

proof = h'{{ $proofFixtures.bls12-381-sha-256.proof001.proof }}'
]]>
</artwork>
</section>

<section anchor="valid-multi-message-all-messages-disclosed-proof-1"><name>Valid Multi-Message, All Messages Disclosed Proof</name>

<artwork><![CDATA[m_1 = h'{{ $proofFixtures.bls12-381-sha-256.proof002.messages[0] }}'
m_2 = h'{{ $proofFixtures.bls12-381-sha-256.proof002.messages[1] }}'
m_3 = h'{{ $proofFixtures.bls12-381-sha-256.proof002.messages[2] }}'
m_4 = h'{{ $proofFixtures.bls12-381-sha-256.proof002.messages[3] }}'
m_5 = h'{{ $proofFixtures.bls12-381-sha-256.proof002.messages[4] }}'
m_6 = h'{{ $proofFixtures.bls12-381-sha-256.proof002.messages[5] }}'
m_7 = h'{{ $proofFixtures.bls12-381-sha-256.proof002.messages[6] }}'
m_8 = h'{{ $proofFixtures.bls12-381-sha-256.proof002.messages[7] }}'
m_9 = h'{{ $proofFixtures.bls12-381-sha-256.proof002.messages[8] }}'
m_10 = h'{{ $proofFixtures.bls12-381-sha-256.proof002.messages[9] }}'

public_key = h'{{ $proofFixtures.bls12-381-sha-256.proof002.signerPublicKey }}'
signature = h'{{ $proofFixtures.bls12-381-sha-256.proof002.signature }}'
header = h'{{ $proofFixtures.bls12-381-sha-256.proof002.header }}'
presentation_header = h'{{ $proofFixtures.bls12-381-sha-256.proof002.presentationHeader }}'
revealed_indexes = {{ $proofFixtures.bls12-381-sha-256.proof002.disclosedIndexes }}

random scalars:
    r1 = 0x'{{ $proofFixtures.bls12-381-sha-256.proof002.trace.random_scalars.r1 }}'
    r2 = 0x'{{ $proofFixtures.bls12-381-sha-256.proof002.trace.random_scalars.r2 }}'
    e_tilde = 0x'{{ $proofFixtures.bls12-381-sha-256.proof002.trace.random_scalars.e_tilde }}'
    r1_tilde = 0x'{{ $proofFixtures.bls12-381-sha-256.proof002.trace.random_scalars.r1_tilde }}'
    r3_tilde = 0x'{{ $proofFixtures.bls12-381-sha-256.proof002.trace.random_scalars.r3_tilde }}'
    m_tilde_scalars: {{ $proofFixtures.bls12-381-sha-256.proof002.trace.random_scalars.m_tilde_scalars }}

T1 = h'{{ $proofFixtures.bls12-381-sha-256.proof002.trace.T1 }}'
T2 = h'{{ $proofFixtures.bls12-381-sha-256.proof002.trace.T2 }}'
domain = 0x'{{ $proofFixtures.bls12-381-sha-256.proof002.trace.domain }}'

proof = h'{{ $proofFixtures.bls12-381-sha-256.proof002.proof }}'
]]>
</artwork>
</section>

<section anchor="valid-multi-message-some-messages-disclosed-proof-1"><name>Valid Multi-Message, Some Messages Disclosed Proof</name>

<artwork><![CDATA[m_1 = h'{{ $proofFixtures.bls12-381-sha-256.proof003.messages[0] }}'
m_2 = h'{{ $proofFixtures.bls12-381-sha-256.proof003.messages[1] }}'
m_3 = h'{{ $proofFixtures.bls12-381-sha-256.proof003.messages[2] }}'
m_4 = h'{{ $proofFixtures.bls12-381-sha-256.proof003.messages[3] }}'
m_5 = h'{{ $proofFixtures.bls12-381-sha-256.proof003.messages[4] }}'
m_6 = h'{{ $proofFixtures.bls12-381-sha-256.proof003.messages[5] }}'
m_7 = h'{{ $proofFixtures.bls12-381-sha-256.proof003.messages[6] }}'
m_8 = h'{{ $proofFixtures.bls12-381-sha-256.proof003.messages[7] }}'
m_9 = h'{{ $proofFixtures.bls12-381-sha-256.proof003.messages[8] }}'
m_10 = h'{{ $proofFixtures.bls12-381-sha-256.proof003.messages[9] }}'

public_key = h'{{ $proofFixtures.bls12-381-sha-256.proof003.signerPublicKey }}'
signature = h'{{ $proofFixtures.bls12-381-sha-256.proof003.signature }}'
header = h'{{ $proofFixtures.bls12-381-sha-256.proof003.header }}'
presentation_header = h'{{ $proofFixtures.bls12-381-sha-256.proof003.presentationHeader }}'
revealed_indexes = {{ $proofFixtures.bls12-381-sha-256.proof003.disclosedIndexes }}

random scalars:
    r1 = 0x'{{ $proofFixtures.bls12-381-sha-256.proof003.trace.random_scalars.r1 }}'
    r2 = 0x'{{ $proofFixtures.bls12-381-sha-256.proof003.trace.random_scalars.r2 }}'
    e_tilde = 0x'{{ $proofFixtures.bls12-381-sha-256.proof003.trace.random_scalars.e_tilde }}'
    r1_tilde = 0x'{{ $proofFixtures.bls12-381-sha-256.proof003.trace.random_scalars.r1_tilde }}'
    r3_tilde = 0x'{{ $proofFixtures.bls12-381-sha-256.proof003.trace.random_scalars.r3_tilde }}'
    m_tilde_scalars:
        m~_1 = 0x'{{ $proofFixtures.bls12-381-sha-256.proof003.trace.random_scalars.m_tilde_scalars[0] }}'
        m~_3 = 0x'{{ $proofFixtures.bls12-381-sha-256.proof003.trace.random_scalars.m_tilde_scalars[1] }}'
        m~_5 = 0x'{{ $proofFixtures.bls12-381-sha-256.proof003.trace.random_scalars.m_tilde_scalars[2] }}'
        m~_7 = 0x'{{ $proofFixtures.bls12-381-sha-256.proof003.trace.random_scalars.m_tilde_scalars[3] }}'
        m~_8 = 0x'{{ $proofFixtures.bls12-381-sha-256.proof003.trace.random_scalars.m_tilde_scalars[4] }}'
        m~_9 = 0x'{{ $proofFixtures.bls12-381-sha-256.proof003.trace.random_scalars.m_tilde_scalars[5] }}'

T1 = h'{{ $proofFixtures.bls12-381-sha-256.proof003.trace.T1 }}'
T2 = h'{{ $proofFixtures.bls12-381-sha-256.proof003.trace.T2 }}'
domain = 0x'{{ $proofFixtures.bls12-381-sha-256.proof003.trace.domain }}'

proof = h'{{ $proofFixtures.bls12-381-sha-256.proof003.proof }}'
]]>
</artwork>
</section>
</section>
</section>
</section>

<section anchor="iana-considerations"><name>IANA Considerations</name>
<t>This document does not make any requests of IANA.</t>
</section>

<section anchor="acknowledgements"><name>Acknowledgements</name>
<t>The authors would like to acknowledge the significant amount of academic work that preceded the development of this document. In particular the original work of <xref target="BBS04"/> which was subsequently developed in <xref target="ASM06"/> <xref target="CL04"/> <xref target="BBDT16"/> <xref target="CDL16"/> and in <xref target="TZ23"/>. This last academic work is the one mostly used by this document.</t>
<t>The current state of this document is the product of the work of the Decentralized Identity Foundation Applied Cryptography Working group, which includes numerous active participants. In particular, the following individuals contributed ideas, feedback and wording that influenced this specification:</t>
<t>Orie Steele, Christian Paquin, Alessandro Guggino, Tomislav Markovski and Greg Bernstein.</t>
<t>Additionally, the authors would like to acknowledge Jacques Traore and Antoine Dumanois, for their crucial contributions to this document.</t>
</section>

</middle>

<back>
<references><name>References</name>
<references><name>Normative References</name>
<reference anchor="DRBG" target="https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf">
  <front>
    <title>Recommendation for Random Number Generation Using Deterministic Random Bit Generators</title>
    <author>
      <organization>NIST</organization>
    </author>
  </front>
</reference>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4086.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8017.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8937.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9380.xml"/>
<reference anchor="SHA2" target="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf">
  <front>
    <title>Secure Hash Standard (SHS)</title>
    <author>
      <organization>NIST</organization>
    </author>
  </front>
</reference>
<reference anchor="SHA3" target="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf">
  <front>
    <title>SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions</title>
    <author>
      <organization>NIST</organization>
    </author>
  </front>
</reference>
</references>
<references><name>Informative References</name>
<reference anchor="ADR02" target="https://doi.org/10.1007/3-540-46035-7_6">
  <front>
    <title>On the Security of Joint Signature and Encryption</title>
    <author fullname="Jee Hea An" initials="J. H." surname="An">
      <organization>SoftMax Inc.</organization>
    </author>
    <author fullname="Yevgeniy Dodis" initials="Y." surname="Dodis">
      <organization>New York University</organization>
    </author>
    <author fullname="Tal Rabin" initials="T." surname="Rabin">
      <organization>IBM T.J. Watson Research Center</organization>
    </author>
    <date year="2002" month="April"/>
  </front>
  <seriesInfo name="In" value="EUROCRYPT"/>
  <seriesInfo name="pages" value="83-107"/>
</reference>
<reference anchor="ASM06" target="https://link.springer.com/chapter/10.1007/11832072_8">
  <front>
    <title>Constant-Size Dynamic k-TAA</title>
    <author fullname="Man Ho Au" initials="M. H." surname="Au"/>
    <author fullname="Willy Susilo" initials="W." surname="Susilo"/>
    <author fullname="Yi Mu" initials="Y." surname="Mu"/>
    <date year="2006"/>
  </front>
  <seriesInfo name="In" value="International Conference on Security and Cryptography for Networks"/>
  <seriesInfo name="pages" value="111-125"/>
  <seriesInfo name="Springer," value="Berlin, Heidelberg"/>
</reference>
<reference anchor="BBB17" target="https://ia.cr/2017/1066">
  <front>
    <title>Bulletproofs: Short Proofs for Confidential Transactions and More</title>
    <author fullname="Benedikt Bunz" initials="B." surname="Bunz">
      <organization>Stanford University</organization>
    </author>
    <author fullname="Jonathan Bootle" initials="J." surname="Bootle">
      <organization>University College London</organization>
    </author>
    <author fullname="Dan Boneh" initials="D." surname="Boneh">
      <organization>Stanford University</organization>
    </author>
    <author fullname="Andrew Poelstra" initials="A." surname="Poelstra">
      <organization>Blockstream</organization>
    </author>
    <author fullname="Pieter Wuille" initials="P." surname="Wuille">
      <organization>Blockstream</organization>
    </author>
    <author fullname="Greg Maxwell" initials="G." surname="Maxwell"/>
    <date year="2017"/>
  </front>
  <seriesInfo name="In" value="2018 IEEE Symposium on Security and Privacy "/>
</reference>
<reference anchor="BBDT16" target="https://link.springer.com/chapter/10.1007/978-3-319-69453-5_20">
  <front>
    <title>Improved Algebraic MACs and Practical Keyed-Verification Anonymous Credentials</title>
    <author fullname="Amira Barki" initials="A." surname="Barki">
      <organization>Orange Labs</organization>
    </author>
    <author fullname="Solenn Brunet" initials="S." surname="Brunet">
      <organization>Orange Labs</organization>
    </author>
    <author fullname="Nicolas Desmoulins" initials="N." surname="Desmoulins">
      <organization>Orange Labs</organization>
    </author>
    <author fullname="Jacques Traore" initials="J." surname="Traore">
      <organization>Orange Labs</organization>
    </author>
    <date year="1016"/>
  </front>
  <seriesInfo name="In" value="International Conference on Selected Areas in Cryptography"/>
</reference>
<reference anchor="BBS04" target="https://link.springer.com/chapter/10.1007/978-3-540-28628-8_3">
  <front>
    <title>Short Group Signatures</title>
    <author fullname="Dan Boneh" initials="D." surname="Boneh"/>
    <author fullname="Xavier Boyen" initials="X." surname="Boyen"/>
    <author fullname="Hovav Scacham" initials="H." surname="Shacham"/>
    <date year="2004"/>
  </front>
  <seriesInfo name="In" value="Advances in Cryptology"/>
  <seriesInfo name="pages" value="41-55"/>
</reference>
<reference anchor="Bowe19" target="https://eprint.iacr.org/2019/814">
  <front>
    <title>Faster subgroup checks for BLS12-381</title>
    <author fullname="Sean Bowe" initials="S." surname="Bowe">
      <organization>Electric Coin Company</organization>
    </author>
    <date year="2019" month="July"/>
  </front>
</reference>
<reference anchor="CDL16" target="https://eprint.iacr.org/2016/663.pdf">
  <front>
    <title>Anonymous Attestation Using the Strong Diffie Hellman Assumption Revisited</title>
    <author fullname="Jan Camenisch" initials="J." surname="Camenisch">
      <organization>IBM Research</organization>
    </author>
    <author fullname="Manu Drijvers" initials="M." surname="Drijvers">
      <organization>Department of Computer Science, ETH Zurich</organization>
    </author>
    <author fullname="Anja Lehmann" initials="A." surname="Lehmann">
      <organization>IBM Research</organization>
    </author>
    <date year="2016"/>
  </front>
  <seriesInfo name="In" value="International Conference on Trust and Trustworthy Computing"/>
  <seriesInfo name="pages" value="1-20"/>
  <seriesInfo name="Springer," value="Cham"/>
</reference>
<reference anchor="CL04" target="https://link.springer.com/chapter/10.1007/978-3-540-28628-8_4">
  <front>
    <title>Signature Schemes and Anonymous Credentials from Bilinear Maps</title>
    <author fullname="Jan Camenisch" initials="J." surname="Camenisch"/>
    <author fullname="Anna Lysyanskaya" initials="A." surname="Lysyanskaya"/>
    <date year="2004"/>
  </front>
  <seriesInfo name="In" value="Annual International Cryptology Conference"/>
  <seriesInfo name="pages" value="56-72"/>
</reference>
<reference anchor="DMS04" target="https://svn-archive.torproject.org/svn/projects/design-paper/tor-design.html">
  <front>
    <title>Tor: The Second-Generation Onion Router</title>
    <author fullname="Roger Dingledine" initials="R." surname="Dingledine">
      <organization>The Free Haven Projecth</organization>
    </author>
    <author fullname="Nick Mathewson" initials="N." surname="Mathewson">
      <organization>The Free Haven Projecth</organization>
    </author>
    <author fullname="Paul Syverson" initials="P." surname="Syverson">
      <organization>Naval Research Lab</organization>
    </author>
    <date year="2004"/>
  </front>
</reference>
<reference anchor="HDWH12" target="https://www.usenix.org/system/files/conference/usenixsecurity12/sec12-final228.pdf">
  <front>
    <title>Mining your Ps and Qs: Detection of widespread weak keys in network devices</title>
    <author fullname="Nadia Heninger" initials="N." surname="Heninger">
      <organization>University of California, San Diego</organization>
    </author>
    <author fullname="Zakir Durumeric" initials="Z." surname="Durumeric">
      <organization>The University of Michigan</organization>
    </author>
    <author fullname="Eric Wustrow" initials="E." surname="Wustrow">
      <organization>The University of Michigan</organization>
    </author>
    <author fullname="J. Alex Halderman" initials="J. A." surname="Halderman">
      <organization>The University of Michigan</organization>
    </author>
    <date year="2012" month="August"/>
  </front>
  <seriesInfo name="In" value="USENIX Security"/>
  <seriesInfo name="pages" value="205-220"/>
</reference>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-jose-json-web-proof.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-lwig-curve-representations.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-pquip-pqc-engineers.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-privacypass-key-consistency.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.irtf-cfrg-bls-signature.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.irtf-cfrg-pairing-friendly-curves.xml"/>
<reference anchor="ISO8601" target="https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf">
  <front>
    <title>Date and time - Representations for information interchange - Part 1: Basic rules</title>
    <author>
      <organization>ISO</organization>
    </author>
  </front>
</reference>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3629.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4648.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9449.xml"/>
<reference anchor="TZ23" target="https://ia.cr/2023/275">
  <front>
    <title>Revisiting BBS Signatures</title>
    <author fullname="Stefano Tessaro" initials="S." surname="Tessaro">
      <organization>University of Washington</organization>
    </author>
    <author fullname="Chenzhi Zhu" initials="C." surname="Zhu">
      <organization>University of Washington</organization>
    </author>
    <date year="2023"/>
  </front>
  <seriesInfo name="In" value="EUROCRYPT"/>
</reference>
<reference anchor="UPROVE" target="https://github.com/microsoft/uprove-node-reference/blob/main/doc/U-Prove%20Cryptographic%20Specification%20V1.1%20Revision%205.pdf">
  <front>
    <title>U-Prove Cryptographic Specification V1.1 Revision 5</title>
    <author>
      <organization>Microsoft Research</organization>
    </author>
  </front>
</reference>
<reference anchor="VB22" target="https://link.springer.com/chapter/10.1007/978-3-030-95312-6_17">
  <front>
    <title>Dynamic universal accumulator with batch update over bilinear groups</title>
    <author fullname="Vitto Giuseppe" initials="V." surname="Giuseppe">
      <organization>University of Luxembourg</organization>
    </author>
    <author fullname="Alex Biryukov" initials="A." surname="Biryukov">
      <organization>University of Luxembourg</organization>
    </author>
    <date year="2022"/>
  </front>
</reference>
<reference anchor="ZCASH-REVIEW" target="https://research.nccgroup.com/wp-content/uploads/2020/07/NCC_Group_Zcash2018_Public_Report_2019-01-30_v1.3.pdf">
  <front>
    <title>Zcash Overwinter Consensus and Sapling Cryptography Review</title>
    <author>
      <organization>NCC Group</organization>
    </author>
  </front>
</reference>
</references>
</references>

<section anchor="bls12-381-hash-to-curve-definition-using-shake-256"><name>BLS12-381 hash_to_curve Definition Using SHAKE-256</name>
<t>The following defines a hash_to_curve suite <xref target="RFC9380"/> for the BLS12-381 curve for both the G1 and G2 subgroups using the extendable output function (xof) of SHAKE-256 as per the guidance defined in section 8.9 of <xref target="RFC9380"/>.</t>
<t>Note the notation used in the below definitions is sourced from <xref target="RFC9380"/>.</t>

<section anchor="bls12-381-g1"><name>BLS12-381 G1</name>
<t>The suite of <tt>BLS12381G1_XOF:SHAKE-256_SSWU_RO_</tt> is defined as follows:</t>

<artwork><![CDATA[* encoding type: hash_to_curve (Section 3 of
                 [@!RFC9380])

* E: y^2 = x^3 + 4

* p: 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f624
     1eabfffeb153ffffb9feffffffffaaab

* r: 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001

* m: 1

* k: 128

* expand_message: expand_message_xof (Section 5.3.2 of
                  [@!RFC9380])

* hash: SHAKE-256

* L: 64

* f: Simplified SWU for AB == 0 (Section 6.6.3 of
     [@!RFC9380])

* Z: 11

*  E': y'^2 = x'^3 + A' * x' + B', where

      -  A' = 0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aef
                d881ac98936f8da0e0f97f5cf428082d584c1d

      -  B' = 0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14f
                cef35ef55a23215a316ceaa5d1cc48e98e172be0

*  iso_map: the 11-isogeny map from E' to E given in Appendix E.2 of
            [@!RFC9380]

*  h_eff: 0xd201000000010001
]]>
</artwork>
<t>Note that the <tt>h_eff</tt> values for this suite are copied from that defined for the <tt>BLS12381G1_XMD:SHA-256_SSWU_RO_</tt> suite defined in section 8.8.1 of <xref target="RFC9380"/>.</t>
<t>An optimized example implementation of the Simplified SWU mapping to the curve E' isogenous to BLS12-381 G1 is given in Appendix F.2 <xref target="RFC9380"/>.</t>
</section>
</section>

<section anchor="the-bls12-381-curve"><name>The BLS12-381 Curve</name>
<t>This section defines BLS12-381. The definitions of this section have been originally described in <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/>, where they are discussed in greater detail.</t>
<t>BLS12-381 are Barreto-Lynn-Scott curves, defined by two elliptic curves <tt>E1</tt> and <tt>E2</tt>, parameterized by an integer <tt>t</tt>. In the case of BLS12-381, <tt>t</tt> is defined as,</t>

<artwork><![CDATA[t = -2^63 - 2^62 - 2^60 - 2^57 - 2^48 - 2^16
]]>
</artwork>
<t>The curves <tt>E1</tt> and <tt>E2</tt> are defined over the finite fields <tt>GF(p)</tt> and <tt>GF(p^2)</tt> correspondingly, where <tt>p</tt> is defined as,</t>

<artwork><![CDATA[p = (t - 1)^2 * (t^4 - t^2 + 1) / 3 + t
]]>
</artwork>
<t>Let <tt>(1, I)</tt> be the bases of the finite field <tt>GF(p^2)</tt>, where <tt>I ^ 2 + 1 = 0</tt> in <tt>GF(p^2)</tt>. We will denote an element <tt>y</tt> of <tt>GF(p^2)</tt> as a tuple <tt>y = (y_0, y_1)</tt>, where <tt>y_0</tt> and <tt>y_1</tt> elements of <tt>GF(p)</tt> for which it holds <tt>y = y_0 * 1 + y_1 * I</tt>. The two elliptic curves are defined by the following equations,</t>

<artwork><![CDATA[E1: y ^ 2 = x ^ 3 + 4
E2: y ^ 2 = x ^ 3 + 4 * (I + 1)
]]>
</artwork>
<t>The group <tt>G1</tt> and <tt>G2</tt> are defined as the the order <tt>r</tt> subgroup of <tt>E1</tt> defined over <tt>GF(p)</tt> and <tt>E2</tt> defined over <tt>GF(p^2)</tt> correspondingly, where <tt>r</tt> is defined as,</t>

<artwork><![CDATA[r = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001
]]>
</artwork>
<t>Note that <tt>r</tt> is a prime factor of <tt>p</tt>. The target group <tt>G_T</tt> is defined as the finite group <tt>GF(p^12)</tt> minus the element <tt>0</tt>.</t>
<t>The base points of BLS12-381, encoded to octets using the procedure defined in <xref target="point-serialization"/> and then represented in hexadecimal format, are defined as,</t>

<artwork><![CDATA[BP1 = h'97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac58
        6c55e83ff97a1aeffb3af00adb22c6bb'
BP2 = h'93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049
       334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051
       c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8'
]]>
</artwork>

<section anchor="optimal-ate-pairing"><name>Optimal Ate pairing</name>
<t>This section describes the optimal Ate pairing for BLS12-381. The pairing computation uses the following utility function.</t>

<artwork><![CDATA[res = Line_function(Q1, Q2, P)

Inputs:

- Q1 (REQUIRED), point of G2.
- Q2 (REQUIRED), point of G2.
- P (REQUIRED), point of G1.

Outputs:

- res: an element on the target group G_T.

Procedure:

1. (x_1, y_1) = Q1
2. (x_2, y_2) = Q2
3. (x, y) = P
4. if Q1 = Q2, set l = (3 * x_1^2) / (2 * y_1)
5. else if Q1 = - Q2, return x - x_1
6. else set l = (y_2 - y_1) / (x_2 - x_1)
7. return (l * (x - x_1) + y_1 - y)
]]>
</artwork>
<t>Let <tt>c = t</tt> for <tt>t</tt> as defined above (<xref target="the-bls12-381-curve"/>) and <tt>c_0, c_1, ... , c_L</tt> in <tt>(-1, 0, 1)</tt> such that the sum of <tt>c_i * 2^i</tt> for <tt>i = 0, 1, ..., L</tt> equals <tt>c</tt>.</t>
<t>Given a point <tt>P</tt> of <tt>G1</tt>, and a point <tt>Q</tt> of <tt>G2</tt>, the output <tt>h(P, Q)</tt> where <tt>h</tt> the Ate pairing for BLS12-381 is calculated as follows,</t>

<artwork><![CDATA[1.  set f = 1 and T = Q
2.  if c_L = -1, set T = -T
3.  for i in (L-1, L-2, ..., 1, 0)
4.      f = f^2 * Line_function(T, T, P)
5.      T = T + T
6.      if c_i = 1,
7.          f = f * Line_function(T, Q, P)
8.          T = T + Q
9.      else if c_i = -1,
10.         f = f * Line_function(T, -Q, P)
11.         T = T - Q
12. f = f ^ ((p ^ 12 - 1) / r)
13. return f
]]>
</artwork>
</section>

<section anchor="point-encoding"><name>Point Encoding</name>
<t>This section defines point encoding and decoding procedures for BLS12-381. Although more flexible point encoding procedures may exist (for example <xref target="I-D.ietf-lwig-curve-representations"/>), the vast majority of current libraries implementing BLS12-381 use (most of them explicitly) the encoding method defined in Appendix C of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/>. For this reason, the ciphersuites defined in <xref target="bls12-381-ciphersuites"/>, use those encoding and decoding procedures. For completeness, those operations are defined in this section as well. See <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/> for a more detailed explanation of the encoding and decoding steps. Note also that we will only consider compressed point encoding (in contrast to <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/>, which supports both compressed and uncompressed point encoding).</t>
<t>In this section we will use the following notation,</t>

<ul spacing="compact">
<li>For an octet string <tt>x</tt>, <tt>x[0]</tt> will denote the first octet (i.e., 8 most significant bits) of <tt>x</tt>.</li>
<li>On input an element <tt>y</tt> of <tt>GF(p)</tt> or <tt>GF(p^2)</tt>, <tt>sqrt(y)</tt> will return the square root of that element in the respective group, i.e., an element <tt>a</tt> such that <tt>a^2 = y</tt>, or INVALID.</li>
<li>For clarity, we will use <tt>Identity_E1</tt>, <tt>Identity_E2</tt> to denote the identity points of <tt>E1</tt> and <tt>E2</tt> correspondingly (note that <tt>Identity_E1</tt> is the same point as <tt>Identity_G1</tt> and <tt>Identity_E2</tt> is the same point as <tt>Identity_G2</tt>).</li>
</ul>
<t>We first have to define the following utility operations.</t>
<t>The following procedure returns one bit corresponding to the sign of an element of <tt>GF(p)</tt>.</t>

<artwork><![CDATA[res = sign_GF_p(y)

Inputs:

- y (REQUIRED), point of the GF(p) group

Outputs:

- res, either 0 or 1

Procedure:

1. if y > (p - 1) / 2, return 1
2. return 0
]]>
</artwork>
<t>The following procedure returns one bit corresponding to the sign of an element in <tt>GF(p^2)</tt>.</t>

<artwork><![CDATA[res = sign_GF_p^2(y)

Inputs:

- y (REQUIRED), point of the GF(p^2) group

Outputs:

- res, either 0 or 1

Procedure:

1. (y_0, y_1) = y
2. if y_1 is 0, return sign_GF_p(y_0)
3. if y_1 > (p - 1) / 2, return 1
4. return 0
]]>
</artwork>

<section anchor="point-serialization"><name>Point Serialization</name>
<t>Let <tt>P = (x, y)</tt> the point to be serialized.</t>
<t>Compute three metadata bits <tt>C_bit</tt>, <tt>I_bit</tt>, and <tt>S_bit</tt>, as follows,</t>

<ol spacing="compact">
<li><tt>C_bit</tt> is set to 1 (indicating that point compression is used).</li>
<li><tt>I_bit</tt> is 1 if <tt>P</tt> is either the <tt>Identity_E1</tt> or <tt>Identity_E2</tt> points, otherwise it is 0.</li>
<li><tt>S_bit</tt> is 0 if <tt>I_bit</tt> is 1 (again note that the ciphersuites described in this document always use point compression). Otherwise (i.e., when point compression is used and <tt>P</tt> is not the identity point of its respective curve), if <tt>P</tt> is a point on <tt>E1</tt>, set <tt>S_bit = sign_GF_p(y)</tt>, else if <tt>P</tt> is a point on <tt>E2</tt>, <tt>S_bit = sign_GF_p^2(y)</tt>.</li>
</ol>
<t>Let <tt>m = (C_bit * 2^7) + (I_bit * 2^6) + (S_bit * 2^5)</tt> and set <tt>m_byte = I2OSP(m, 1)</tt>. Define <tt>x_string</tt> as follows,</t>

<ol spacing="compact">
<li>If <tt>P = Identity_E1</tt>, set <tt>x_string = I2OSP(0, 48)</tt>.</li>
<li>If <tt>P</tt> is a point on <tt>E1</tt> and <tt>P != Identity_E1</tt>, set <tt>x_string = I2OSP(x, 48)</tt>.</li>
<li>If <tt>P = Identity_E2</tt>, set <tt>x_string = I2OSP(0, 96)</tt>.</li>
<li>If <tt>P</tt> is a point on <tt>E2</tt> and <tt>P != Identity_E2</tt>, then let <tt>x_0</tt> and <tt>x_1</tt> elements of <tt>GF(p)</tt> such that <tt>x = (x_0, x_1)</tt> and set <tt>x_string = I2OSP(x_1, 48) || I2OSP(x_0, 48)</tt>.</li>
</ol>
<t>Let <tt>s_string = x_string</tt>. Set <tt>s_string[0] = x_string[0] OR m_byte</tt>, where <tt>OR</tt> is computed for each bit. Output <tt>s_string</tt> as the serialization result of the point <tt>P</tt>.</t>
</section>

<section anchor="point-de-serialization"><name>Point De-serialization</name>
<t>Let <tt>m_byte = s_string[0] AND 0xE0</tt>, where <tt>AND</tt> is computed bitwise. If <tt>m_byte</tt> equals <tt>0x20</tt> or <tt>0x60</tt> or <tt>0xE0</tt>, output INVALID and abort the operation. Otherwise, let <tt>C_bit</tt> equal the most significant bit of <tt>m_byte</tt>, <tt>I_bit</tt> equal the second most significant bit of <tt>m_byte</tt>, and <tt>S_bit</tt> equal the third most significant bit of <tt>m_byte</tt>. If <tt>C_bit</tt> is 0 return INVALID and abort the operation (note again that we only consider compressed encoding).</t>

<ol>
<li><t>Determine the curve of the encoded point as follows,</t>

<ul spacing="compact">
<li>If <tt>s_string</tt> has length 48 octets, the encoded point is on the curve <tt>E1</tt>.</li>
<li>If <tt>s_string</tt> has length 96 octets, the encoded point is on the curve <tt>E2</tt>.</li>
<li>If <tt>s_string</tt> has any other length, output INVALID and abort the operation.</li>
</ul></li>
<li><t>Let <tt>s_string[0] = s_string[0] AND 0x1F</tt>, where <tt>AND</tt> is computed bitwise (this will set the three most significant bits of <tt>s_string[0]</tt> to 0).</t>
</li>
<li><t>If <tt>I_bit</tt> is 1, then the encoded point must be the Identity point of the curve determined on step 1. If <tt>s_string</tt> is not the all zeros string, output INVALID and abort the operation. Otherwise, output the Identity point of the curve that was determined in step 1 (i.e., either <tt>Identity_E1</tt> or <tt>Identity_E2</tt>).</t>
</li>
<li><t>Let <tt>x = OS2IP(s_string)</tt>.</t>
</li>
<li><t>If the curve that was determined in step 1 is <tt>E1</tt>,</t>

<ul spacing="compact">
<li>Let <tt>y2 = x^3 + 4</tt> in <tt>GF(p)</tt>.</li>
<li>If <tt>y2</tt> is not square in <tt>GF(p)</tt>, output INVALID and abort the operation. Otherwise, let <tt>y = sqrt(y2)</tt> in <tt>GF(p)</tt> and set <tt>Y_bit = sign_GF_p(y)</tt>.</li>
</ul></li>
<li><t>If the curve that was determined in step 1 is <tt>E2</tt>,</t>

<ul spacing="compact">
<li>Let <tt>y2 = x^3 + 4 * (I + 1)</tt> in <tt>GF(p^2)</tt>.</li>
<li>If <tt>y2</tt> is not square in <tt>GF(p^2)</tt>, output INVALID and abort the operation. Otherwise, let <tt>y = sqrt(y2)</tt> in <tt>GF(p^2)</tt> and set <tt>Y_bit = sign_GF_p^2(y)</tt>.</li>
</ul></li>
<li><t>If <tt>S_bit</tt> equals <tt>Y_bit</tt>, output <tt>P = (x, y)</tt>. Otherwise, output <tt>P = (x, -y)</tt>.</t>
</li>
</ol>
</section>
</section>
</section>

<section anchor="use-cases"><name>Use Cases</name>

<section anchor="non-correlating-security-token"><name>Non-correlating Security Token</name>
<t>In the most general sense BBS signatures can be used in any application where a cryptographically secured token is required but correlation caused by usage of the token is un-desirable.</t>
<t>For example in protocols like OAuth2.0 the most commonly used form of the access token leverages the JWT format alongside conventional cryptographic primitives such as traditional digital signatures or HMACs. These access tokens are then used by a relying party to prove authority to a resource server during a request. However, because the access token is most commonly sent by value as it was issued by the authorization server (e.g., in a bearer style scheme), the access token can act as a source of strong correlation for the relying party. Relevant prior art can be found <eref target="https://www.ietf.org/archive/id/draft-private-access-tokens-01.html">here</eref>.</t>
<t>BBS Signatures due to their unique properties removes this source of correlation but maintains the same set of guarantees required by a resource server to validate an access token back to its relevant authority (note that an approach to signing JSON tokens with BBS that may be of relevance is the JSON Web Proofs (JWP) format and serialization described in <xref target="I-D.ietf-jose-json-web-proof"/>). In the context of a protocol like OAuth2.0 the access token issued by the authorization server would feature a BBS Signature, however instead of the relying party providing this access token as issued, in their request to a resource server, they generate a unique proof from the original access token and include that in the request instead, thus removing this vector of correlation.</t>
</section>

<section anchor="improved-bearer-security-token"><name>Improved Bearer Security Token</name>
<t>Bearer based security tokens such as JWT based access tokens used in the OAuth2.0 protocol are a highly popular format for expressing authorization grants. However their usage has several security limitations. Notably a bearer based authorization scheme often has to rely on a secure transport between the authorized party (client) and the resource server to mitigate the potential for a MITM attack or a malicious interception of the access token. The scheme also has to assume a degree of trust in the resource server it is presenting an access token to, particularly when the access token grants more than just access to the target resource server, because in a bearer based authorization scheme, anyone who possesses the access token has authority to what it grants. Bearer based access tokens also suffer from the threat of replay attacks.</t>
<t>Improved schemes around authorization protocols often involve adding a layer of proof of cryptographic key possession to the presentation of an access token, which mitigates the deficiencies highlighted above as well as providing a way to detect a replay attack. However, approaches that involve proof of cryptographic key possession such as DPoP (<xref target="RFC9449"/>), suffer from an increase in protocol complexity. A party requesting authorization must pre-generate appropriate key material, share the public portion of this with the authorization server alongside proving possession of the private portion of the key material. The authorization server must also be-able to accommodate receiving this information and validating it.</t>
<t>BBS Signatures offer an alternative model that solves the same problems that proof of cryptographic key possession schemes do for bearer based schemes, but in a way that doesn't introduce new up-front protocol complexity. In the context of a protocol like OAuth2.0 the access token issued by the authorization server would feature a BBS Signature, however instead of the client providing this access token as issued, in their request to a resource server, they generate a unique proof from the original access token and include that in the request instead. Because the access token is not shared in a request to a resource server, attacks such as MITM are mitigated. A resource server also obtains the ability to detect a replay attack by ensuring the proof presented is unique.</t>
</section>

<section anchor="selectively-disclosure-enabled-identity-credentials"><name>Selectively Disclosure Enabled Identity Credentials</name>
<t>BBS signatures when applied to the problem space of identity credentials can help to enhance user privacy. For example a digital drivers license that is cryptographically signed with a BBS signature, allows the holder or subject of the license (acting as the Prover of the BBS scheme) to disclose different claims from their drivers license to different parties. Furthermore, the unlinkable presentations property of proofs generated by the scheme remove an important possible source of correlation for the holder across multiple presentations.</t>
</section>
</section>

<section anchor="additional-test-vectors"><name>Additional Test Vectors</name>

<section anchor="bls12-381-shake-256-ciphersuite"><name>BLS12-381-SHAKE-256 Ciphersuite</name>

<section anchor="signature-test-vectors"><name>Signature Test Vectors</name>

<section anchor="no-header-valid-signature"><name>No Header Valid Signature</name>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-shake-256.signature010.messages[0] }}'
m_2 = h'{{ $signatureFixtures.bls12-381-shake-256.signature010.messages[1] }}'
m_3 = h'{{ $signatureFixtures.bls12-381-shake-256.signature010.messages[2] }}'
m_4 = h'{{ $signatureFixtures.bls12-381-shake-256.signature010.messages[3] }}'
m_5 = h'{{ $signatureFixtures.bls12-381-shake-256.signature010.messages[4] }}'
m_6 = h'{{ $signatureFixtures.bls12-381-shake-256.signature010.messages[5] }}'
m_7 = h'{{ $signatureFixtures.bls12-381-shake-256.signature010.messages[6] }}'
m_8 = h'{{ $signatureFixtures.bls12-381-shake-256.signature010.messages[7] }}'
m_9 = h'{{ $signatureFixtures.bls12-381-shake-256.signature010.messages[8] }}'
m_10 = h'{{ $signatureFixtures.bls12-381-shake-256.signature010.messages[9] }}'

SK = 0x'{{ $signatureFixtures.bls12-381-shake-256.signature010.signerKeyPair.secretKey }}'
PK = h'{{ $signatureFixtures.bls12-381-shake-256.signature010.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-shake-256.signature010.header }}'

B = h'{{ $signatureFixtures.bls12-381-shake-256.signature010.trace.B }}'
domain = 0x'{{ $signatureFixtures.bls12-381-shake-256.signature010.trace.domain }}'

signature = h'{{ $signatureFixtures.bls12-381-shake-256.signature010.signature }}'
]]>
</artwork>
</section>

<section anchor="modified-message-signature"><name>Modified Message Signature</name>
<t>The following fixture should fail signature validation due to the message value being different from what was signed.</t>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-shake-256.signature002.messages[0] }}'

PK = h'{{ $signatureFixtures.bls12-381-shake-256.signature002.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-shake-256.signature002.header }}'

signature = h'{{ $signatureFixtures.bls12-381-shake-256.signature002.signature }}'

valid: {{ $signatureFixtures.bls12-381-shake-256.signature002.result.valid }}
reason: {{ $signatureFixtures.bls12-381-shake-256.signature002.result.reason }}
]]>
</artwork>
</section>

<section anchor="extra-unsigned-message-signature"><name>Extra Unsigned Message Signature</name>
<t>The following fixture should fail signature validation due to an additional message being supplied that was not signed.</t>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-shake-256.signature003.messages[0] }}'
m_2 = h'{{ $signatureFixtures.bls12-381-shake-256.signature003.messages[1] }}'

PK = h'{{ $signatureFixtures.bls12-381-shake-256.signature003.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-shake-256.signature003.header }}'

signature = h'{{ $signatureFixtures.bls12-381-shake-256.signature003.signature }}'

valid: {{ $signatureFixtures.bls12-381-shake-256.signature003.result.valid }}
reason: {{ $signatureFixtures.bls12-381-shake-256.signature003.result.reason }}
]]>
</artwork>
</section>

<section anchor="missing-message-signature"><name>Missing Message Signature</name>
<t>The following fixture should fail signature validation due to missing messages that were originally present during the signing (the presented signature was generated with all the messages in <xref target="messages-1"/> as input).</t>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-shake-256.signature005.messages[0] }}'
m_2 = h'{{ $signatureFixtures.bls12-381-shake-256.signature005.messages[1] }}'

PK = h'{{ $signatureFixtures.bls12-381-shake-256.signature005.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-shake-256.signature005.header }}'

signature = h'{{ $signatureFixtures.bls12-381-shake-256.signature005.signature }}'

valid: {{ $signatureFixtures.bls12-381-shake-256.signature005.result.valid }}
reason: {{ $signatureFixtures.bls12-381-shake-256.signature005.result.reason }}
]]>
</artwork>
</section>

<section anchor="reordered-message-signature"><name>Reordered Message Signature</name>
<t>The following fixture should fail signature validation due to messages being re-ordered from the order in which they were signed.</t>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-shake-256.signature006.messages[0] }}'
m_2 = h'{{ $signatureFixtures.bls12-381-shake-256.signature006.messages[1] }}'
m_3 = h'{{ $signatureFixtures.bls12-381-shake-256.signature006.messages[2] }}'
m_4 = h'{{ $signatureFixtures.bls12-381-shake-256.signature006.messages[3] }}'
m_5 = h'{{ $signatureFixtures.bls12-381-shake-256.signature006.messages[4] }}'
m_6 = h'{{ $signatureFixtures.bls12-381-shake-256.signature006.messages[5] }}'
m_7 = h'{{ $signatureFixtures.bls12-381-shake-256.signature006.messages[6] }}'
m_8 = h'{{ $signatureFixtures.bls12-381-shake-256.signature006.messages[7] }}'
m_9 = h'{{ $signatureFixtures.bls12-381-shake-256.signature006.messages[8] }}'
m_10 = h'{{ $signatureFixtures.bls12-381-shake-256.signature006.messages[9] }}'

PK = h'{{ $signatureFixtures.bls12-381-shake-256.signature006.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-shake-256.signature006.header }}'

signature = h'{{ $signatureFixtures.bls12-381-shake-256.signature006.signature }}'

valid: {{ $signatureFixtures.bls12-381-shake-256.signature006.result.valid }}
reason: {{ $signatureFixtures.bls12-381-shake-256.signature006.result.reason }}
]]>
</artwork>
</section>

<section anchor="wrong-public-key-signature"><name>Wrong Public Key Signature</name>
<t>The following fixture should fail signature validation due to public key used to verify is in-correct.</t>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-shake-256.signature007.messages[0] }}'
m_2 = h'{{ $signatureFixtures.bls12-381-shake-256.signature007.messages[1] }}'
m_3 = h'{{ $signatureFixtures.bls12-381-shake-256.signature007.messages[2] }}'
m_4 = h'{{ $signatureFixtures.bls12-381-shake-256.signature007.messages[3] }}'
m_5 = h'{{ $signatureFixtures.bls12-381-shake-256.signature007.messages[4] }}'
m_6 = h'{{ $signatureFixtures.bls12-381-shake-256.signature007.messages[5] }}'
m_7 = h'{{ $signatureFixtures.bls12-381-shake-256.signature007.messages[6] }}'
m_8 = h'{{ $signatureFixtures.bls12-381-shake-256.signature007.messages[7] }}'
m_9 = h'{{ $signatureFixtures.bls12-381-shake-256.signature007.messages[8] }}'
m_10 = h'{{ $signatureFixtures.bls12-381-shake-256.signature007.messages[9] }}'

PK = h'{{ $signatureFixtures.bls12-381-shake-256.signature007.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-shake-256.signature007.header }}'

signature = h'{{ $signatureFixtures.bls12-381-shake-256.signature007.signature }}'

valid: {{ $signatureFixtures.bls12-381-shake-256.signature007.result.valid }}
reason: {{ $signatureFixtures.bls12-381-shake-256.signature007.result.reason }}
]]>
</artwork>
</section>

<section anchor="wrong-header-signature"><name>Wrong Header Signature</name>
<t>The following fixture should fail signature validation due to header value being modified from what was originally signed.</t>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-shake-256.signature008.messages[0] }}'
m_2 = h'{{ $signatureFixtures.bls12-381-shake-256.signature008.messages[1] }}'
m_3 = h'{{ $signatureFixtures.bls12-381-shake-256.signature008.messages[2] }}'
m_4 = h'{{ $signatureFixtures.bls12-381-shake-256.signature008.messages[3] }}'
m_5 = h'{{ $signatureFixtures.bls12-381-shake-256.signature008.messages[4] }}'
m_6 = h'{{ $signatureFixtures.bls12-381-shake-256.signature008.messages[5] }}'
m_7 = h'{{ $signatureFixtures.bls12-381-shake-256.signature008.messages[6] }}'
m_8 = h'{{ $signatureFixtures.bls12-381-shake-256.signature008.messages[7] }}'
m_9 = h'{{ $signatureFixtures.bls12-381-shake-256.signature008.messages[8] }}'
m_10 = h'{{ $signatureFixtures.bls12-381-shake-256.signature008.messages[9] }}'

PK = h'{{ $signatureFixtures.bls12-381-shake-256.signature008.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-shake-256.signature008.header }}'

signature = h'{{ $signatureFixtures.bls12-381-shake-256.signature008.signature }}'

valid: {{ $signatureFixtures.bls12-381-shake-256.signature008.result.valid }}
reason: {{ $signatureFixtures.bls12-381-shake-256.signature008.result.reason }}
]]>
</artwork>
</section>
</section>

<section anchor="proof-test-vectors"><name>Proof Test Vectors</name>

<section anchor="no-header-valid-proof"><name>No Header Valid Proof</name>

<artwork><![CDATA[m_1 = h'{{ $proofFixtures.bls12-381-shake-256.proof014.messages[0] }}'
m_2 = h'{{ $proofFixtures.bls12-381-shake-256.proof014.messages[1] }}'
m_3 = h'{{ $proofFixtures.bls12-381-shake-256.proof014.messages[2] }}'
m_4 = h'{{ $proofFixtures.bls12-381-shake-256.proof014.messages[3] }}'
m_5 = h'{{ $proofFixtures.bls12-381-shake-256.proof014.messages[4] }}'
m_6 = h'{{ $proofFixtures.bls12-381-shake-256.proof014.messages[5] }}'
m_7 = h'{{ $proofFixtures.bls12-381-shake-256.proof014.messages[6] }}'
m_8 = h'{{ $proofFixtures.bls12-381-shake-256.proof014.messages[7] }}'
m_9 = h'{{ $proofFixtures.bls12-381-shake-256.proof014.messages[8] }}'
m_10 = h'{{ $proofFixtures.bls12-381-shake-256.proof014.messages[9] }}'

public_key = h'{{ $proofFixtures.bls12-381-shake-256.proof014.signerPublicKey }}'
signature = h'{{ $proofFixtures.bls12-381-shake-256.proof014.signature }}'
header = h'{{ $proofFixtures.bls12-381-shake-256.proof014.header }}'
presentation_header = h'{{ $proofFixtures.bls12-381-shake-256.proof014.presentationHeader }}'
revealed_indexes = {{ $proofFixtures.bls12-381-shake-256.proof014.disclosedIndexes }}

T1 = h'{{ $proofFixtures.bls12-381-shake-256.proof014.trace.T1 }}'
T2 = h'{{ $proofFixtures.bls12-381-shake-256.proof014.trace.T2 }}'
domain = 0x'{{ $proofFixtures.bls12-381-shake-256.proof014.trace.domain }}'

proof = h'{{ $proofFixtures.bls12-381-shake-256.proof014.proof }}'
]]>
</artwork>
</section>

<section anchor="no-presentation-header-valid-proof"><name>No Presentation Header Valid Proof</name>

<artwork><![CDATA[m_1 = h'{{ $proofFixtures.bls12-381-shake-256.proof015.messages[0] }}'
m_2 = h'{{ $proofFixtures.bls12-381-shake-256.proof015.messages[1] }}'
m_3 = h'{{ $proofFixtures.bls12-381-shake-256.proof015.messages[2] }}'
m_4 = h'{{ $proofFixtures.bls12-381-shake-256.proof015.messages[3] }}'
m_5 = h'{{ $proofFixtures.bls12-381-shake-256.proof015.messages[4] }}'
m_6 = h'{{ $proofFixtures.bls12-381-shake-256.proof015.messages[5] }}'
m_7 = h'{{ $proofFixtures.bls12-381-shake-256.proof015.messages[6] }}'
m_8 = h'{{ $proofFixtures.bls12-381-shake-256.proof015.messages[7] }}'
m_9 = h'{{ $proofFixtures.bls12-381-shake-256.proof015.messages[8] }}'
m_10 = h'{{ $proofFixtures.bls12-381-shake-256.proof015.messages[9] }}'

public_key = h'{{ $proofFixtures.bls12-381-shake-256.proof015.signerPublicKey }}'
signature = h'{{ $proofFixtures.bls12-381-shake-256.proof015.signature }}'
header = h'{{ $proofFixtures.bls12-381-shake-256.proof015.header }}'
presentation_header = h'{{ $proofFixtures.bls12-381-shake-256.proof015.presentationHeader }}'
revealed_indexes = {{ $proofFixtures.bls12-381-shake-256.proof015.disclosedIndexes }}

T1 = h'{{ $proofFixtures.bls12-381-shake-256.proof015.trace.T1 }}'
T2 = h'{{ $proofFixtures.bls12-381-shake-256.proof015.trace.T2 }}'
domain = 0x'{{ $proofFixtures.bls12-381-shake-256.proof015.trace.domain }}'

proof = h'{{ $proofFixtures.bls12-381-shake-256.proof015.proof }}'
]]>
</artwork>
</section>
</section>

<section anchor="hash-to-scalar-test-vectors"><name>Hash to Scalar Test Vectors</name>
<t>Using the following input message,</t>

<artwork><![CDATA[msg = h'{{ $H2sFixture.bls12-381-shake-256.h2s.message }}'
]]>
</artwork>
<t>And following dst value,</t>

<artwork><![CDATA[dst = h'{{ $H2sFixture.bls12-381-shake-256.h2s.dst }}'
]]>
</artwork>
<t>We get the following scalar output from <tt>hash_to_scalar</tt> (<xref target="hash-to-scalar"/>), encoded with I2OSP and represented in big endian order,</t>

<artwork><![CDATA[scalar = 0x'{{ $H2sFixture.bls12-381-shake-256.h2s.scalar }}
]]>
</artwork>
</section>
</section>

<section anchor="bls12-381-sha-256-ciphersuite"><name>BLS12-381-SHA-256 Ciphersuite</name>

<section anchor="signature-test-vectors-1"><name>Signature Test Vectors</name>

<section anchor="no-header-valid-signature-1"><name>No Header Valid Signature</name>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-sha-256.signature010.messages[0] }}'
m_2 = h'{{ $signatureFixtures.bls12-381-sha-256.signature010.messages[1] }}'
m_3 = h'{{ $signatureFixtures.bls12-381-sha-256.signature010.messages[2] }}'
m_4 = h'{{ $signatureFixtures.bls12-381-sha-256.signature010.messages[3] }}'
m_5 = h'{{ $signatureFixtures.bls12-381-sha-256.signature010.messages[4] }}'
m_6 = h'{{ $signatureFixtures.bls12-381-sha-256.signature010.messages[5] }}'
m_7 = h'{{ $signatureFixtures.bls12-381-sha-256.signature010.messages[6] }}'
m_8 = h'{{ $signatureFixtures.bls12-381-sha-256.signature010.messages[7] }}'
m_9 = h'{{ $signatureFixtures.bls12-381-sha-256.signature010.messages[8] }}'
m_10 = h'{{ $signatureFixtures.bls12-381-sha-256.signature010.messages[9] }}'

SK = 0x'{{ $signatureFixtures.bls12-381-sha-256.signature010.signerKeyPair.secretKey }}'
PK = h'{{ $signatureFixtures.bls12-381-sha-256.signature010.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-sha-256.signature010.header }}'

B = h'{{ $signatureFixtures.bls12-381-sha-256.signature010.trace.B }}'
domain = 0x'{{ $signatureFixtures.bls12-381-sha-256.signature010.trace.domain }}'

signature = h'{{ $signatureFixtures.bls12-381-sha-256.signature010.signature }}'
]]>
</artwork>
</section>

<section anchor="modified-message-signature-1"><name>Modified Message Signature</name>
<t>The following fixture should fail signature validation due to the message value being different from what was signed.</t>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-sha-256.signature002.messages[0] }}'

SK = 0x'{{ $signatureFixtures.bls12-381-sha-256.signature002.signerKeyPair.secretKey }}'
PK = h'{{ $signatureFixtures.bls12-381-sha-256.signature002.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-sha-256.signature002.header }}'

signature = h'{{ $signatureFixtures.bls12-381-sha-256.signature002.signature }}'

valid: {{ $signatureFixtures.bls12-381-sha-256.signature002.result.valid }}
reason: {{ $signatureFixtures.bls12-381-sha-256.signature002.result.reason }}
]]>
</artwork>
</section>

<section anchor="extra-unsigned-message-signature-1"><name>Extra Unsigned Message Signature</name>
<t>The following fixture should fail signature validation due to an additional message being supplied that was not signed.</t>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-sha-256.signature003.messages[0] }}'
m_2 = h'{{ $signatureFixtures.bls12-381-sha-256.signature003.messages[1] }}'

SK = 0x'{{ $signatureFixtures.bls12-381-sha-256.signature003.signerKeyPair.secretKey }}'
PK = h'{{ $signatureFixtures.bls12-381-sha-256.signature003.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-sha-256.signature003.header }}'

signature = h'{{ $signatureFixtures.bls12-381-sha-256.signature003.signature }}'

valid: {{ $signatureFixtures.bls12-381-sha-256.signature003.result.valid }}
reason: {{ $signatureFixtures.bls12-381-sha-256.signature003.result.reason }}
]]>
</artwork>
</section>

<section anchor="missing-message-signature-1"><name>Missing Message Signature</name>
<t>The following fixture should fail signature validation due to missing messages that were originally present during the signing (the presented signature was generated with all the messages in <xref target="messages-1"/> as input).</t>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-sha-256.signature005.messages[0] }}'
m_2 = h'{{ $signatureFixtures.bls12-381-sha-256.signature005.messages[1] }}'

SK = 0x'{{ $signatureFixtures.bls12-381-sha-256.signature005.signerKeyPair.secretKey }}'
PK = h'{{ $signatureFixtures.bls12-381-sha-256.signature005.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-sha-256.signature005.header }}'

signature = h'{{ $signatureFixtures.bls12-381-sha-256.signature005.signature }}'

valid: {{ $signatureFixtures.bls12-381-sha-256.signature005.result.valid }}
reason: {{ $signatureFixtures.bls12-381-sha-256.signature005.result.reason }}
]]>
</artwork>
</section>

<section anchor="reordered-message-signature-1"><name>Reordered Message Signature</name>
<t>The following fixture should fail signature validation due to messages being re-ordered from the order in which they were signed.</t>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-sha-256.signature006.messages[0] }}'
m_2 = h'{{ $signatureFixtures.bls12-381-sha-256.signature006.messages[1] }}'
m_3 = h'{{ $signatureFixtures.bls12-381-sha-256.signature006.messages[2] }}'
m_4 = h'{{ $signatureFixtures.bls12-381-sha-256.signature006.messages[3] }}'
m_5 = h'{{ $signatureFixtures.bls12-381-sha-256.signature006.messages[4] }}'
m_6 = h'{{ $signatureFixtures.bls12-381-sha-256.signature006.messages[5] }}'
m_7 = h'{{ $signatureFixtures.bls12-381-sha-256.signature006.messages[6] }}'
m_8 = h'{{ $signatureFixtures.bls12-381-sha-256.signature006.messages[7] }}'
m_9 = h'{{ $signatureFixtures.bls12-381-sha-256.signature006.messages[8] }}'
m_10 = h'{{ $signatureFixtures.bls12-381-sha-256.signature006.messages[9] }}'

SK = 0x'{{ $signatureFixtures.bls12-381-sha-256.signature006.signerKeyPair.secretKey }}'
PK = h'{{ $signatureFixtures.bls12-381-sha-256.signature006.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-sha-256.signature006.header }}'

signature = h'{{ $signatureFixtures.bls12-381-sha-256.signature006.signature }}'

valid: {{ $signatureFixtures.bls12-381-sha-256.signature006.result.valid }}
reason: {{ $signatureFixtures.bls12-381-sha-256.signature006.result.reason }}
]]>
</artwork>
</section>

<section anchor="wrong-public-key-signature-1"><name>Wrong Public Key Signature</name>
<t>The following fixture should fail signature validation due to public key used to verify is in-correct.</t>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-sha-256.signature007.messages[0] }}'
m_2 = h'{{ $signatureFixtures.bls12-381-sha-256.signature007.messages[1] }}'
m_3 = h'{{ $signatureFixtures.bls12-381-sha-256.signature007.messages[2] }}'
m_4 = h'{{ $signatureFixtures.bls12-381-sha-256.signature007.messages[3] }}'
m_5 = h'{{ $signatureFixtures.bls12-381-sha-256.signature007.messages[4] }}'
m_6 = h'{{ $signatureFixtures.bls12-381-sha-256.signature007.messages[5] }}'
m_7 = h'{{ $signatureFixtures.bls12-381-sha-256.signature007.messages[6] }}'
m_8 = h'{{ $signatureFixtures.bls12-381-sha-256.signature007.messages[7] }}'
m_9 = h'{{ $signatureFixtures.bls12-381-sha-256.signature007.messages[8] }}'
m_10 = h'{{ $signatureFixtures.bls12-381-sha-256.signature007.messages[9] }}'

SK = 0x'{{ $signatureFixtures.bls12-381-sha-256.signature007.signerKeyPair.secretKey }}'
PK = h'{{ $signatureFixtures.bls12-381-sha-256.signature007.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-sha-256.signature007.header }}'

signature = h'{{ $signatureFixtures.bls12-381-sha-256.signature007.signature }}'

valid: {{ $signatureFixtures.bls12-381-sha-256.signature007.result.valid }}
reason: {{ $signatureFixtures.bls12-381-sha-256.signature007.result.reason }}
]]>
</artwork>
</section>

<section anchor="wrong-header-signature-1"><name>Wrong Header Signature</name>
<t>The following fixture should fail signature validation due to header value being modified from what was originally signed.</t>

<artwork><![CDATA[m_1 = h'{{ $signatureFixtures.bls12-381-sha-256.signature008.messages[0] }}'
m_2 = h'{{ $signatureFixtures.bls12-381-sha-256.signature008.messages[1] }}'
m_3 = h'{{ $signatureFixtures.bls12-381-sha-256.signature008.messages[2] }}'
m_4 = h'{{ $signatureFixtures.bls12-381-sha-256.signature008.messages[3] }}'
m_5 = h'{{ $signatureFixtures.bls12-381-sha-256.signature008.messages[4] }}'
m_6 = h'{{ $signatureFixtures.bls12-381-sha-256.signature008.messages[5] }}'
m_7 = h'{{ $signatureFixtures.bls12-381-sha-256.signature008.messages[6] }}'
m_8 = h'{{ $signatureFixtures.bls12-381-sha-256.signature008.messages[7] }}'
m_9 = h'{{ $signatureFixtures.bls12-381-sha-256.signature008.messages[8] }}'
m_10 = h'{{ $signatureFixtures.bls12-381-sha-256.signature008.messages[9] }}'

SK = 0x'{{ $signatureFixtures.bls12-381-sha-256.signature008.signerKeyPair.secretKey }}'
PK = h'{{ $signatureFixtures.bls12-381-sha-256.signature008.signerKeyPair.publicKey }}'
header = h'{{ $signatureFixtures.bls12-381-sha-256.signature008.header }}'

signature = h'{{ $signatureFixtures.bls12-381-sha-256.signature008.signature }}'

valid: {{ $signatureFixtures.bls12-381-sha-256.signature008.result.valid }}
reason: {{ $signatureFixtures.bls12-381-sha-256.signature008.result.reason }}
]]>
</artwork>
</section>
</section>

<section anchor="proof-test-vectors-1"><name>Proof Test Vectors</name>

<section anchor="no-header-valid-proof-1"><name>No Header Valid Proof</name>

<artwork><![CDATA[m_1 = h'{{ $proofFixtures.bls12-381-sha-256.proof014.messages[0] }}'
m_2 = h'{{ $proofFixtures.bls12-381-sha-256.proof014.messages[1] }}'
m_3 = h'{{ $proofFixtures.bls12-381-sha-256.proof014.messages[2] }}'
m_4 = h'{{ $proofFixtures.bls12-381-sha-256.proof014.messages[3] }}'
m_5 = h'{{ $proofFixtures.bls12-381-sha-256.proof014.messages[4] }}'
m_6 = h'{{ $proofFixtures.bls12-381-sha-256.proof014.messages[5] }}'
m_7 = h'{{ $proofFixtures.bls12-381-sha-256.proof014.messages[6] }}'
m_8 = h'{{ $proofFixtures.bls12-381-sha-256.proof014.messages[7] }}'
m_9 = h'{{ $proofFixtures.bls12-381-sha-256.proof014.messages[8] }}'
m_10 = h'{{ $proofFixtures.bls12-381-sha-256.proof014.messages[9] }}'

public_key = h'{{ $proofFixtures.bls12-381-sha-256.proof014.signerPublicKey }}'
signature = h'{{ $proofFixtures.bls12-381-sha-256.proof014.signature }}'
header = h'{{ $proofFixtures.bls12-381-sha-256.proof014.header }}'
presentation_header = h'{{ $proofFixtures.bls12-381-sha-256.proof014.presentationHeader }}'
revealed_indexes = {{ $proofFixtures.bls12-381-sha-256.proof014.disclosedIndexes }}

T = h'{{ $proofFixtures.bls12-381-sha-256.proof014.trace.T }}'
domain = 0x'{{ $proofFixtures.bls12-381-sha-256.proof014.trace.domain }}'
challenge = 0x'{{ $proofFixtures.bls12-381-sha-256.proof014.trace.challenge }}'

proof = h'{{ $proofFixtures.bls12-381-sha-256.proof014.proof }}'
]]>
</artwork>
</section>

<section anchor="no-presentation-header-valid-proof-1"><name>No Presentation Header Valid Proof</name>

<artwork><![CDATA[m_1 = h'{{ $proofFixtures.bls12-381-sha-256.proof015.messages[0] }}'
m_2 = h'{{ $proofFixtures.bls12-381-sha-256.proof015.messages[1] }}'
m_3 = h'{{ $proofFixtures.bls12-381-sha-256.proof015.messages[2] }}'
m_4 = h'{{ $proofFixtures.bls12-381-sha-256.proof015.messages[3] }}'
m_5 = h'{{ $proofFixtures.bls12-381-sha-256.proof015.messages[4] }}'
m_6 = h'{{ $proofFixtures.bls12-381-sha-256.proof015.messages[5] }}'
m_7 = h'{{ $proofFixtures.bls12-381-sha-256.proof015.messages[6] }}'
m_8 = h'{{ $proofFixtures.bls12-381-sha-256.proof015.messages[7] }}'
m_9 = h'{{ $proofFixtures.bls12-381-sha-256.proof015.messages[8] }}'
m_10 = h'{{ $proofFixtures.bls12-381-sha-256.proof015.messages[9] }}'

public_key = h'{{ $proofFixtures.bls12-381-sha-256.proof015.signerPublicKey }}'
signature = h'{{ $proofFixtures.bls12-381-sha-256.proof015.signature }}'
header = h'{{ $proofFixtures.bls12-381-sha-256.proof015.header }}'
presentation_header = h'{{ $proofFixtures.bls12-381-sha-256.proof015.presentationHeader }}'
revealed_indexes = {{ $proofFixtures.bls12-381-sha-256.proof015.disclosedIndexes }}

T1 = h'{{ $proofFixtures.bls12-381-sha-256.proof015.trace.T1 }}'
T2 = h'{{ $proofFixtures.bls12-381-sha-256.proof015.trace.T2 }}'
domain = 0x'{{ $proofFixtures.bls12-381-sha-256.proof015.trace.domain }}'

proof = h'{{ $proofFixtures.bls12-381-sha-256.proof015.proof }}'
]]>
</artwork>
</section>
</section>

<section anchor="hash-to-scalar-test-vectors-1"><name>Hash to Scalar Test Vectors</name>
<t>Using the following input message,</t>

<artwork><![CDATA[msg = h'{{ $H2sFixture.bls12-381-sha-256.h2s.message }}'
]]>
</artwork>
<t>And following dst value,</t>

<artwork><![CDATA[dst = h'{{ $H2sFixture.bls12-381-sha-256.h2s.dst }}'
]]>
</artwork>
<t>We get the following scalar output from <tt>hash_to_scalar</tt> (<xref target="hash-to-scalar"/>), encoded with I2OSP and represented in big endian order,</t>

<artwork><![CDATA[scalar = 0x'{{ $H2sFixture.bls12-381-sha-256.h2s.scalar }}'
]]>
</artwork>
</section>
</section>
</section>

<section anchor="proof-generation-and-verification-algorithmic-explanation"><name>Proof Generation and Verification Algorithmic Explanation</name>
<t>The following section provides a high-level explanation of how the <tt>CoreProofGen</tt> and <tt>CoreProofVerify</tt> operations work, as presented in Appendix B of <xref target="TZ23"/> and used by this document. The <tt>CoreProofGen</tt> procedure uses a generic non-interactive zero-knowledge proof-of-knowledge (<tt>NIZK</tt>) protocol, executed between a Prover and a Verifier. A <tt>NIZK</tt> works as follows; Assume the group points <tt>J_0</tt>, <tt>J_1</tt>, ..., <tt>J_n</tt> and the exponents <tt>e_0</tt>, <tt>e_1</tt>, ..., <tt>e_n</tt>. Assume also that all the group points are publicly known, while only the exponent <tt>e_0</tt> is known to the Verifier of the <tt>NIZK</tt> and the exponents <tt>e_1</tt>, ..., <tt>e_n</tt> are known only by the Prover of the protocol. The <tt>NIZK</tt> can be used to prove a relationship of the form,</t>

<artwork><![CDATA[J_O * e_0 = J_1 * e_1 + J_2 * e_2 + ... + J_n * e_n
]]>
</artwork>
<t>While revealing nothing about the secret exponents (i.e., <tt>e_1</tt>, ..., <tt>e_n</tt>), other than the fact that the Prover knows them.</t>
<t>For BBS, let the Prover be in possession of a BBS signature <tt>(A, e)</tt> on messages <tt>msg_1, ..., msg_L</tt> and a <tt>domain</tt> value (see  <tt>CoreSign</tt> defined in <xref target="coresign"/>). Let <tt>A = B * (1/(e + SK))</tt> where <tt>SK</tt> the Signer's secret key and,</t>

<artwork><![CDATA[[1]	B = P1 + Q_1 * domain + H_1 * msg_1 + ... + H_L * msg_L
]]>
</artwork>
<t>Let <tt>(i1, ..., iR)</tt> be the indexes of the messages the Prover wants to disclose and <tt>(j1, ..., jU)</tt> be the indexes corresponding to undisclosed messages (i.e., <tt>(j1, ..., jU) = (1, 2, ..., L) \ (i1, ..., iR)</tt>). To prove knowledge of a signature on the disclosed messages, work as follows;</t>

<ul>
<li><t>Prove possession of a valid signature. As defined above, a signature <tt>(A, e)</tt>, on messages <tt>msg_1, ..., msg_L</tt> is valid if <tt>A = B * 1/(e + SK)</tt>, where <tt>B</tt> as in [1]. However, the Prover cannot reveal neither <tt>A</tt>, <tt>e</tt> nor <tt>B</tt> to the Verifier (signature is uniquely identifiable and <tt>B</tt> will reveal information about the signed messages, even the undisclosed ones). To get around this, the Prover needs to hide the signature <tt>(A, e)</tt> and the value of <tt>B</tt>, in a way that will allow proving knowledge of such elements with the aforementioned relationship (i.e., that <tt>A = B * 1/(e + SK)</tt>), without revealing their value. The Prover will do this by randomizing them. To do that, they take uniformly random <tt>r1, r2</tt> in <tt>[1, r-1]</tt>, and calculate,</t>

<artwork><![CDATA[[2]	Abar = A * (r1 * r2)
[3]	D = B * r2
[4]	Bbar = D * r1 + Abar * (-e)
]]>
</artwork>
<t>The values <tt>(Abar, D, Bbar)</tt> will be part of the proof and are used to prove possession of a BBS signature, without revealing the signature itself. Note that; if <tt>Abar</tt> and <tt>Bbar</tt> are constructed using a valid BBS signature as above, then <tt>Abar * SK = Bbar</tt> which is equivalent to <tt>h(Abar, PK) = h(Bbar, BP2)</tt>, where <tt>SK</tt>, <tt>PK</tt> the Signer's secret and public key and <tt>BP2</tt> the base generator of <tt>G2</tt> (used to create the Signer’s <tt>PK</tt>, see <xref target="public-key"/>). This last equation is something that the Verifier can check using the Signer's <tt>PK</tt>.</t>
</li>
<li><t>Prove that the disclosed messages are signed as part of that signature. The Prover will start by setting the following,</t>

<artwork><![CDATA[[5]	r2' = (1 / r2) mod r
]]>
</artwork>
<t>If the <tt>Abar</tt>, <tt>D</tt> and <tt>Bbar</tt> values are constructed using a valid BBS signature as in [2], [3] and [4], then the following will hold,</t>

<artwork><![CDATA[[6]	P1 + Q_1 * domain + H_i1 * msg_i1 + ... + H_iR * msg_iR =
                   	D * r2' - H_ji * msg_j1 - ... - H_jU * msg_jU
]]>
</artwork>
</li>
</ul>
<t>Note that the Verifier will know the elements in the left side of [6] (i.e., <tt>P1</tt>, <tt>Q_1</tt>, <tt>H_i1</tt>, ..., <tt>H_iR</tt> and the disclosed messages: <tt>msg_i1</tt>, ..., <tt>msg_iR</tt>) as well as the base points of the right side (i.e., the points <tt>D</tt> and <tt>H_j1, ..., H_jU</tt>). They will not however know the exponents on the right side of [6] (i.e., <tt>r2'</tt> and the undisclosed messages: <tt>msg_j1, ..., msg_jU</tt>). The same holds for equation [4] where the Verifier will know the left side of the equation (i.e., <tt>Bbar</tt>) and the base points of the right side (i.e., <tt>D</tt> and <tt>Abar</tt>) but not the exponents (i.e., <tt>r1</tt> and <tt>-e</tt>).</t>
<t>To convince the Verifier that both [4] and [6] hold, the Prover can use a <tt>NIZK</tt>, to prove that they know the exponents that satisfy those equations, without disclosing them.</t>
<t>Note that if the value <tt>D</tt> is constructed correctly (as in [3]), then <tt>B = D * r2'</tt>. Proving knowledge of [6] corresponds to proving knowledge of <tt>r2'</tt>, which means that the Prover does actually know a value <tt>B = D * r2'</tt>. If [6] holds, then that <tt>B</tt> value that the Prover knows (i.e., <tt>D * r2'</tt>) will also have the "correct form" for <tt>B</tt> (as in [1]), including all (the disclosed and "some" undisclosed) messages.</t>
<t>All that remains is proving that this <tt>B</tt> value the Prover knows, is also "signed" by the Signer i.e., that the Prover also knows values <tt>A</tt> and <tt>e</tt>, such that <tt>A = B * 1/(e + SK)</tt> or, equivalently, that <tt>h(A, PK + BP2 * e) = h(B, BP2)</tt>, which is what <tt>CoreVerify</tt> checks to validate a signature (see <xref target="coreverify"/>).</t>
<t>Note that, the Prover will use a <tt>NIZK</tt> to showcase (among other things), knowledge of values <tt>r1</tt> and <tt>e</tt> so that [4] holds (<tt>Bbar</tt>, <tt>D</tt> and <tt>Abar</tt> will be part of the proof and hence known to the Verifier). Setting <tt>r1' = (1 / r1) mod r</tt> (note that proving knowledge of <tt>r1</tt> indirectly proves knowledge of <tt>r1'</tt> as well), using [4] and the fact that <tt>h(Abar, PK) = h(Bbar, BP2)</tt> we can get that,</t>

<artwork><![CDATA[h(Abar * r1' * r2', PK + BP2 * e) = h(D * r2', BP2) = h(B, BP2)
]]>
</artwork>
<t>Note that the above is what <tt>CoreVerify</tt> checks, for <tt>A = Abar * r1' * r2'</tt>. Since the Prover showcased knowledge of <tt>r1'</tt> and <tt>r2'</tt> and revealed <tt>Abar</tt> as part of the proof, the Verifier can be assured that the Prover knows the value <tt>A = Abar * r1' * r2'</tt>. So setting <tt>A = Abar * r1' * r2'</tt>, the values <tt>A</tt>, <tt>e</tt>, <tt>B</tt> that the Prover showed knowledge of, will form a valid BBS signature. Note that the Verifier doesn't know <tt>A</tt> (since they don't know <tt>r1'</tt> and <tt>r2'</tt>), <tt>e</tt> or <tt>B</tt> (since they don't know <tt>r2'</tt> or the undisclosed messages). However, they know that the prover knows them and as we saw above, these values form a valid signature on (among others) the disclosed messages.</t>
<t>To sum up; in order to validate the proof, a Verifier checks that <tt>h(Abar, PK) = h(Bbar, BP2)</tt> and verifies the <tt>NIZK</tt>. Validating the proof will guarantee the authenticity and integrity of the disclosed messages, as well as knowledge of the undisclosed messages and of the signature.</t>
</section>

<section anchor="document-history"><name>Document History</name>
<t>-00</t>

<ul spacing="compact">
<li>Initial version</li>
</ul>
<t>-01</t>

<ul spacing="compact">
<li>Populated fixtures</li>
<li>Added SHA-256 based ciphersuite</li>
<li>Fixed typo in ProofVerify</li>
<li>Clarify ASCII string usage in DST</li>
<li>Added MapMessageToScalar test vectors</li>
<li>Fix typo in ciphersuite name</li>
</ul>
<t>-02</t>

<ul spacing="compact">
<li>Variety of editiorial clarifications</li>
<li>Clarified integer endianness</li>
<li>Revised the encode for hash operation</li>
<li>Shifted to using CSPRNG instead of PRF</li>
<li>Removed total number of messages from proof verify operation</li>
<li>Added deterministic proof fixtures</li>
<li>Shifted to multiple CSPRNG calls to calculate random elements, instead of expand_message</li>
<li>Updated hash_to_scalar to a single output</li>
</ul>
<t>-03</t>

<ul spacing="compact">
<li>Updated core operation based on new <eref target="https://eprint.iacr.org/2023/275">academic paper</eref></li>
<li>Variety of editorial updates</li>
<li>Updated exception and error handling</li>
<li>Added extension point for the operation with which the generators are created, allowing ciphersuites to define different operations for creating the generator points.</li>
<li>Added extension point for the operation with which the input messages are mapped to scalar values, allowing ciphersuites to define different message-to-scalar mapping operations</li>
<li>Added signature/proof fixtures with an empty header or an empty presentation header input</li>
<li>Updated the fixtures to use variable length messages (one of which is now the empty message "")</li>
</ul>
<t>-04</t>

<ul spacing="compact">
<li>Restructure Proof Generation and Verification operation to different subroutines.</li>
<li>Separate high-level (Interface) operations from low-level (Core) operations.</li>
<li>Update the ciphersuite ID to remove from it the <tt>create_generators</tt> and <tt>map_message_to_scalar</tt> IDs, since those are defined as part of the high-level interface instead of the ciphersuite.</li>
<li>Add a <tt>commitment</tt> optional value to the <tt>CoreSign</tt> operation. The <tt>commitment</tt> value is added to allow using BBS as part of other protocols but is ignored in this document.</li>
<li>Update test-vectors display.</li>
</ul>
<t>-05</t>

<ul spacing="compact">
<li>Proof Generation and Verification operations updated based on Appendix B of <xref target="TZ23"/>.</li>
<li>Test vectors updated based on the new proof generation procedure.</li>
<li>Removed the optional <tt>commitment</tt> value from the <tt>CoreSign</tt> operation, as the intended use case (blind signatures) will be addressed differently and in another document.</li>
<li>Changed the reference to <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/> from Normative to Informative, by re-defining the relevant functionality to this document.</li>
<li>Various editorial updates.</li>
</ul>
<t>-06</t>

<ul spacing="compact">
<li>To support bounded memory implementations, the order of the inputs to the digest operation for the calculation of the <tt>e</tt> value during <tt>CoreSign</tt> and the <tt>challenge</tt> value during <tt>CoreProofGen</tt> and <tt>CoreProofVerify</tt> was updated.</li>
<li>Updated the test vectores to match the above update.</li>
<li>Renamed the pairing function from <tt>e</tt> to <tt>h</tt>, to avoid naming collisions with the scalar component of the signature.</li>
<li>Renamed <tt>signature_dst</tt>, <tt>challenge_dst</tt> and <tt>domain_dst</tt> to <tt>hash_to_scalar_dst</tt>.</li>
</ul>
<t>-07</t>

<ul spacing="compact">
<li>Editorial fixes (nizk -&gt; NIZK, clarified scalar multiplication in Notation Section).</li>
<li>Removed "subject to change" warning on additional test vectors.</li>
<li>Fixed proof deserialization error.</li>
<li>Fixed order of inputs in <tt>CoreSign</tt> call.</li>
<li>Fixed wrong inputs in <tt>calculate_domain</tt> call in <tt>CoreSign</tt> and <tt>CoreVerify</tt>.</li>
</ul>
</section>

</back>

</rfc>
