<?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-looker-cfrg-bbs-signatures-00" submissionType="IETF" category="info" xml:lang="en" consensus="true">

<front>
<title abbrev="The BBS Signature Scheme">The BBS Signature Scheme</title><seriesInfo value="draft-looker-cfrg-bbs-signatures-00" 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>BBS is a digital signature scheme categorized as a form of short group signature that supports several unique properties. Notably, the scheme supports signing multiple messages whilst producing a single output digital signature. Through this capability, the possessor of a signature is able to generate proofs that selectively disclose subsets of the originally signed set of messages, whilst preserving the verifiable authenticity and integrity of the messages. Furthermore, these proofs are said to be zero-knowledge in nature as they do not reveal the underlying signature; instead, what they reveal is a proof of knowledge of the undisclosed signature.</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>The name BBS is derived from the authors of the original academic work of Dan Boneh, Xavier Boyen, and Hovav Shacham, where the scheme was first described.</t>
<t>Beyond the core properties of a digital signature scheme, BBS signatures 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 holder/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 known as 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, each proof generated is indistinguishable from random even for two proofs 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 (holder/prover) was in possession of a signature without revealing it. The scheme also supports binding a presentation header to the generated proof. The presentation header can include arbitrary information such as a cryptographic nonce, an audience/domain identifier and or time based validity information.</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">  (1) sign                                      (3) ProofGen
   +-----                                         +-----
   |    |                                         |    |
   |    |                                         |    |
   |   \ /                                        |   \ /
+----------+                                   +-----------+
|          |                                   |           |
|          |                                   |           |
|          |                                   |           |
|  Signer  |---(2)* Send signature + msgs-----&gt;|  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>

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

<dl>
<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>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>msg</dt>
<dd>An input message to be signed by the signature scheme.</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>nonce</dt>
<dd>A cryptographic nonce</dd>
<dt>presentation_header (ph)</dt>
<dd>A payload generated and bound to the context of a specific spk.</dd>
<dt>nizk</dt>
<dd>A non-interactive zero-knowledge proof from fiat-shamir heuristic.</dd>
<dt>dst</dt>
<dd>The domain separation tag.</dd>
<dt>I2OSP</dt>
<dd>As defined by Section 4 of <xref target="RFC8017"/></dd>
<dt>OS2IP</dt>
<dd>As defined by Section 4 of <xref target="RFC8017"/>.</dd>
</dl>
</section>

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

<dl>
<dt>a || b</dt>
<dd>Denotes the concatenation of octet strings a and b.</dd>
<dt>I \ J</dt>
<dd>For sets I and J, denotes the difference of the two sets 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>range(a, b)</dt>
<dd>For integers a and b, with a &lt;= b, denotes the ascending ordered list of all integers between a and b inclusive (i.e., the integers "i" such that a &lt;= i &lt;= b).</dd>
<dt>utf8(ascii_string)</dt>
<dd>Encoding the inputted ASCII string to an octet string using UTF-8 character encoding.</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>
</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>
<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.</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>e</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>P1, P2</dt>
<dd>points on G1 and G2 respectively. For a pairing-friendly curve, this document denotes operations in E1 and E2 in additive notation, i.e., P + Q denotes point addition and x * P denotes scalar multiplication. Operations in GT are written in multiplicative notation, i.e., a * b is field multiplication.</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="I-D.irtf-cfrg-hash-to-curve"/> 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>point_to_octets_g1(P) -&gt; ostr, point_to_octets_g2(P) -&gt; ostr</dt>
<dd>returns the canonical representation of the point P for the respective subgroup as an octet string. This operation is also known as serialization.</dd>
<dt>octets_to_point_g1(ostr) -&gt; P, octets_to_point_g2(ostr) -&gt; P</dt>
<dd>returns the point P for the respective subgroup corresponding to the canonical representation ostr, or INVALID if ostr is not a valid output of the respective point_to_octets_g* function. This operation is also known as deserialization.</dd>
<dt>subgroup_check(P) -&gt; VALID or INVALID</dt>
<dd>returns VALID when the point P is an element of the subgroup of order r, 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"/>.</dd>
</dl>
</section>

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

<ul>
<li><t><eref target="#scheme-definition">Scheme Definition</eref> defines the core operations and parameters for the BBS signature scheme.</t>
</li>
<li><t><eref target="#utility-operations">Utility Operations</eref> defines utilities used by the BBS signature scheme.</t>
</li>
<li><t><eref target="#security-considerations">Security Considerations</eref> describes a set of security considerations associated to the signature scheme.</t>
</li>
<li><t><eref target="#ciphersuites">Ciphersuites</eref> 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 ciphersuite.</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 <eref target="#notation">Section 1.2</eref>.</t>
</li>
<li><t>A hash-to-curve suite as defined in <xref target="I-D.irtf-cfrg-hash-to-curve"/>, using the aforementioned pairing-friendly curve. This defines the hash_to_curve and expand_message operations, used by this document.</t>
</li>
<li><t>PRF(n): a pseudo-random function similar to <xref target="RFC4868"/>. Returns n pseudo randomly generated bytes.</t>
</li>
</ul>
</section>

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

<section anchor="subgroup-selection"><name>Subgroup Selection</name>
<t>In definition of this signature scheme there are two possible variations based upon the sub-group 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 cryptography 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 things. However, in the case of this scheme, due to the operations involved in both signature and proof generation being computational in-efficient when performed in G2 and in the pursuit of simplicity, the scheme is limited to a construction where public keys are in G2 and signatures in G1.</t>
</section>

<section anchor="messages-and-generators"><name>Messages and generators</name>
<t>Throughout the operations of this signature scheme, each message that is signed is paired with a specific generator (point in G1). 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).</t>
<t>Aside from the message generators, the scheme uses two additional generators: <tt>Q_1</tt> and <tt>Q_2</tt>. The first (<tt>Q_1</tt>), is used for the blinding value (<tt>s</tt>) of the signature. The second generator (<tt>Q_2</tt>), is used 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 etc.).</t>
</section>
</section>

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

<section anchor="keygen"><name>KeyGen</name>
<t>This operation generates a secret key (SK) deterministically from a secret octet string (IKM).</t>
<t>KeyGen uses an HKDF <xref target="RFC5869"/> instantiated with the hash function hash.</t>
<t>For security, IKM MUST be infeasible to guess, e.g. generated by a trusted source of randomness.</t>
<t>IKM MUST be at least 32 bytes long, but it MAY be longer.</t>
<t>Because KeyGen is deterministic, implementations MAY choose either to store the resulting SK or to store IKM and call KeyGen to derive SK when necessary.</t>
<t>KeyGen takes an optional parameter, key_info. This parameter MAY be used to derive multiple independent keys from the same IKM.  By default, key_info is the empty string.</t>

<artwork>SK = KeyGen(IKM, key_info)

Inputs:

- IKM (REQUIRED), a secret octet string. See requirements above.
- key_info (OPTIONAL), an octet string. if this is not supplied, it
                       MUST default to an empty string.

Definitions:

- HKDF-Extract is as defined in [@!RFC5869], instantiated with hash function hash.
- HKDF-Expand is as defined in [@!RFC5869], instantiated with hash function hash.
- I2OSP and OS2IP are as defined in [@!RFC8017], Section 4.
- L is the integer given by ceil((3 * ceil(log2(r))) / 16).
- INITSALT is the ASCII string "BBS-SIG-KEYGEN-SALT-".

Outputs:

- SK, a uniformly random integer such that 0 &lt; SK &lt; r.

Procedure:

1. salt = INITSALT
2. SK = 0
3. while SK == 0:
4.     salt = hash(salt)
5.     PRK = HKDF-Extract(salt, IKM || I2OSP(0, 1))
6.     OKM = HKDF-Expand(PRK, key_info || I2OSP(L, 2), L)
7.     SK = OS2IP(OKM) mod r
8. return SK
</artwork>
<t><strong>Note</strong> 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 KeyGen procedure. For security, such an alternative MUST output a secret key that is statistically close to uniformly random in the range 0 &lt; SK &lt; r.</t>
</section>

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

<artwork>PK = SkToPk(SK)

Inputs:

- SK (REQUIRED), a secret integer such that 0 &lt; SK &lt; r.

Outputs:

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

Procedure:

1. W = SK * P2
2. return point_to_octets_g2(W)
</artwork>
</section>
</section>

<section anchor="core-operations"><name>Core Operations</name>
<t>The operations in this section make use of a “Precomputations” set of steps. The “Precomputations” steps must be executed before the steps in the “Procedure” of each operation and include computations that can be cached and re-used multiple times (like creating the generators etc.) or procedural steps like de-structuring inputted arrays.</t>

<section anchor="sign"><name>Sign</name>
<t>This operation computes a deterministic signature from a secret key (SK) and optionally over a header and or a vector of messages.</t>

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

Inputs:

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

Parameters:

- ciphersuite_id, ASCII string. The unique ID of the ciphersuite.
- generator_seed, ASCII string. The generators seed defined by the
                  ciphersuite

Definitions:

- L, is the non-negative integer representing the number of messages to
     be signed e.g length(messages). If no messages are supplied as an
     input, the value of L MUST evaluate to zero (0).

Outputs:

- signature, a signature encoded as an octet string.

Precomputations:

1. msg_1, ..., msg_L = messages[1], ..., messages[L]
2. (Q_1, Q_2, H_1, ..., H_L) = create_generators(generator_seed, L+2)

Procedure:

1.  dom_array = (PK, L, Q_1, Q_2, H_1, ..., H_L, ciphersuite_id, header)
2.  dom_for_hash = encode_for_hash(dom_array)
3.  if dom_for_hash is INVALID, return INVALID
4.  domain = hash_to_scalar(dom_for_hash, 1)
5.  e_s_for_hash = encode_for_hash((SK, domain, msg_1, ..., msg_L))
6.  if e_s_for_hash is INVALID, return INVALID
7.  (e, s) = hash_to_scalar(e_s_for_hash, 2)
8.  B = P1 + Q_1 * s + Q_2 * domain + H_1 * msg_1 + ... + H_L * msg_L
9.  A = B * (1 / (SK + e))
10. signature_octets = signature_to_octets(A, e, s)
11. return signature_octets
</artwork>
<t><strong>Note</strong> When computing step 9 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 9, and or <tt>A != Identity_G1</tt> after step 9 to prevent the production of invalid signatures.</t>
</section>

<section anchor="verify"><name>Verify</name>
<t>This operation checks that a signature is valid for a given header and vector of messages against a supplied public key (PK). The messages MUST be supplied in this operation in the same order they were supplied to <eref target="#sign">Sign</eref> when creating the signature.</t>

<artwork>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 an empty string.
- messages (OPTIONAL), a vector of scalars. If not supplied, it defaults
                       to the empty array "()".

Parameters:

- ciphersuite_id, ASCII string. The unique ID of the ciphersuite.
- generator_seed, ASCII string. The generators seed defined by the
                  ciphersuite.

Definitions:

- L, is the non-negative integer representing the number of messages to
     be signed e.g length(messages). If no messages are supplied as an
     input, the value of L MUST evaluate to zero (0).

Outputs:

- result, either VALID or INVALID.

Precomputations:

1. (msg_1, ..., msg_L) = messages
2. (Q_1, Q_2, H_1, ..., H_L) = create_generators(generator_seed, L+2)

Procedure:

1.  signature_result = octets_to_signature(signature)
2.  if signature_result is INVALID, return INVALID
3.  (A, e, s) = signature_result
4.  W = octets_to_pubkey(PK)
5.  if W is INVALID, return INVALID
6.  dom_array = (PK, L, Q_1, Q_2, H_1, ..., H_L, ciphersuite_id, header)
7.  dom_for_hash = encode_for_hash(dom_array)
8.  if dom_for_hash is INVALID, return INVALID
9.  domain = hash_to_scalar(dom_for_hash, 1)
10. B = P1 + Q_1 * s + Q_2 * domain + H_1 * msg_1 + ... + H_L * msg_L
11. if e(A, W + P2 * e) * e(B, -P2) != Identity_GT, return INVALID
12. return VALID
</artwork>
</section>

<section anchor="proofgen"><name>ProofGen</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 presentation header, see <eref target="#presentation-header-selection">Presentation header selection</eref> for more details.</t>
<t>The messages supplied in this operation MUST be in the same order as when supplied to <eref target="#sign">Sign</eref>. 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 1 to <tt>length(messages)</tt>.</t>

<artwork>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 an empty string.
- ph (OPTIONAL), octet string containing the presentation header. If not
                 supplied, it defaults to an empty string.
- messages (OPTIONAL), a vector of scalars. 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:

- ciphersuite_id, ASCII string. The unique ID of the ciphersuite.
- generator_seed, ASCII string. The generators seed defined by the
                  ciphersuite.

Definitions:

- L, is the non-negative integer representing the number of messages,
     i.e., L = length(messages). If no messages are supplied, the
     value of L MUST evaluate to zero (0).
- R, is the non-negative integer representing the number of disclosed
     (revealed) messages, i.e., R = length(disclosed_indexes). If no
     messages are disclosed, R MUST evaluate to zero (0).
- U, is the non-negative integer representing the number of undisclosed
     messages, i.e., U = L - R.
- prf_len = ceil(ceil(log2(r))/8), where r defined by the ciphersuite.

Outputs:

- proof, octet string; or INVALID.

Precomputations:

1. (i1, ..., iR) = disclosed_indexes
2. (j1, ..., jU) = range(1, L) \ disclosed_indexes
3. (msg_1, ..., msg_L) = messages
4. (msg_i1, ..., msg_iR) = (messages[i1], ..., messages[iR])
5. (msg_j1, ..., msg_jU) = (messages[j1], ..., messages[jU])
6. (Q_1, Q_2, MsgGenerators) = create_generators(generator_seed, L+2)
7. (H_1, ..., H_L) = MsgGenerators
8. (H_j1, ..., H_jU) = (MsgGenerators[j1], ..., MsgGenerators[jU])

Procedure:

1.  signature_result = octets_to_signature(signature)
2.  if signature_result is INVALID, return INVALID
3.  (A, e, s) = signature_result
4.  dom_array = (PK, L, Q_1, Q_2, H_1, ..., H_L, ciphersuite_id, header)
5.  dom_for_hash = encode_for_hash(dom_array)
6.  if dom_for_hash is INVALID, return INVALID
7.  domain = hash_to_scalar(dom_for_hash, 1)
8.  (r1, r2, e~, r2~, r3~, s~) = hash_to_scalar(PRF(prf_len), 6)
9.  (m~_j1, ..., m~_jU) = hash_to_scalar(PRF(prf_len), U)
10. B = P1 + Q_1 * s + Q_2 * domain + H_1 * msg_1 + ... + H_L * msg_L
11. r3 = r1 ^ -1 mod r
12. A' = A * r1
13. Abar = A' * (-e) + B * r1
14. D = B * r1 + Q_1 * r2
15. s' = r2 * r3 + s mod r
16. C1 = A' * e~ + Q_1 * r2~
17. C2 = D * (-r3~) + Q_1 * s~ + H_j1 * m~_j1 + ... + H_jU * m~_jU
18. c_array = (A', Abar, D, C1, C2, R, i1, ..., iR,
                       msg_i1, ..., msg_iR, domain, ph)
19. c_for_hash = encode_for_hash(c_array)
20. if c_for_hash is INVALID, return INVALID
21. c = hash_to_scalar(c_for_hash, 1)
22. e^ = c * e + e~ mod r
23. r2^ = c * r2 + r2~ mod r
24. r3^ = c * r3 + r3~ mod r
25. s^ = c * s' + s~ mod r
26. for j in (j1, ..., jU): m^_j = c * msg_j + m~_j mod r
27. proof = (A', Abar, D, c, e^, r2^, r3^, s^, (m^_j1, ..., m^_jU))
28. return proof_to_octets(proof)
</artwork>
</section>

<section anchor="proofverify"><name>ProofVerify</name>
<t>This operation checks that a proof is valid for a header, vector of disclosed messages (along side their index corresponding to their original position when signed) and presentation header against a public key (PK).</t>
<t>The operation accepts the list of messages the prover indicated to be disclosed. Those messages MUST be in the same order as when supplied to <eref target="#sign">Sign</eref> (as a subset of the signed messages list). The operation also requires the total number of signed messages (L). Lastly, it also accepts the indexes that the disclosed messages had in the original array of messages supplied to <eref target="#sign">Sign</eref> (i.e., the <tt>disclosed_indexes</tt> list supplied to <eref target="#proofgen">ProofGen</eref>). Every element in this list MUST be a non-negative integer in the range from 1 to L, in ascending order.</t>

<artwork>result = ProofVerify(PK, proof, L, 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.
- L (REQUIRED), non-negative integer. The number of signed messages.
- header (OPTIONAL), an optional octet string containing context and
                     application specific information. If not supplied,
                     it defaults to an empty string.
- ph (OPTIONAL), octet string containing the presentation header. If not
                 supplied, it defaults to an empty string.
- disclosed_messages (OPTIONAL), a vector of scalars. 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:

- ciphersuite_id, ASCII string. The unique ID of the ciphersuite.
- generator_seed, ASCII string. The generators seed defined by the
                  ciphersuite.

Definitions:

- R, is the non-negative integer representing the number of disclosed
     (revealed) messages, i.e., R = length(disclosed_indexes). If no
     messages are disclosed, the value of R MUST evaluate to zero (0).
- U, is the non-negative integer representing the number of undisclosed
     messages, i.e., U = L - R.

Outputs:

- result, either VALID or INVALID.

Precomputations:

1. (i1, ..., iR) = disclosed_indexes
2. (j1, ..., jU) = range(1, L) \ disclosed_indexes
3. (msg_i1, ..., msg_iR) = disclosed_messages
4. (Q_1, Q_2, MsgGenerators) = create_generators(generator_seed, L+2)
5. (H_1, ..., H_L) = MsgGenerators
6. (H_i1, ..., H_iR) = (MsgGenerators[i1], ..., MsgGenerators[iR])
7. (H_j1, ..., H_jU) = (MsgGenerators[j1], ..., MsgGenerators[jU])

Preconditions:

1. for i in (i1, ..., iR), if i &lt; 1 or i &gt; L, return INVALID
2. if length(disclosed_messages) != R, return INVALID

Procedure:

1.  proof_result = octets_to_proof(proof)
2.  if proof_result is INVALID, return INVALID
3.  (A', Abar, D, c, e^, r2^, r3^, s^, (m^_j1,...,m^_jU)) = proof_result
4.  W = octets_to_pubkey(PK)
5.  if W is INVALID, return INVALID
6.  dom_array = (PK, L, Q_1, Q_2, H_1, ..., H_L, ciphersuite_id, header)
7.  dom_for_hash = encode_for_hash(dom_array)
8.  if dom_for_hash is INVALID, return INVALID
9.  domain = hash_to_scalar(dom_for_hash, 1)
10. C1 = (Abar - D) * c + A' * e^ + Q_1 * r2^
11. T = P1 + Q_2 * domain + H_i1 * msg_i1 + ... H_iR * msg_iR
12. C2 = T * c - D * r3^ + Q_1 * s^ + H_j1 * m^_j1 + ... + H_jU * m^_jU
13. cv_array = (A', Abar, D, C1, C2, R, i1, ..., iR,
                       msg_i1, ..., msg_iR, domain, ph)
14. cv_for_hash = encode_for_hash(cv_array)
15. if cv_for_hash is INVALID, return INVALID
16. cv = hash_to_scalar(cv_for_hash, 1)
17. if c != cv, return INVALID
18. if A' == Identity_G1, return INVALID
19. if e(A', W) * e(Abar, -P2) != Identity_GT, return INVALID
20. return VALID
</artwork>
</section>
</section>
</section>

<section anchor="utility-operations"><name>Utility Operations</name>

<section anchor="generator-point-computation"><name>Generator point computation</name>
<t>This operation defines how to create a set of generators that form a part of the public parameters used by the BBS Signature scheme to accomplish operations such as <eref target="#sign">Sign</eref>, <eref target="#verify">Verify</eref>, <eref target="#proofgen">ProofGen</eref> and <eref target="#proofverify">ProofVerify</eref>. It takes one input, the number of generator points to create, which is determined in part by the number of signed messages.</t>
<t>As an optimization, implementations MAY cache the result of <tt>create_generators</tt> for a specific <tt>generator_seed</tt> (determined by the ciphersuite) and <tt>count</tt>. The values <tt>n</tt> and <tt>v</tt> MAY also be cached in order to efficiently extend a existing list of generator points.</t>

<artwork>generators = create_generators(count)

Inputs:

- count (REQUIRED), unsigned integer. Number of generators to create.

Parameters:

- hash_to_curve_suite, the hash to curve suite id defined by the
                       ciphersuite.
- 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.
- expand_message, the expand_message operation defined by the suite
                  specified by the hash_to_curve_suite parameter.
- generator_seed, octet string. A seed value selected by the
                  ciphersuite.

Definitions:

- seed_dst, the octet string representing the ASCII encoded characters:
           "BBS_" || hash_to_curve_suite || "SIG_GENERATOR_SEED_".
- generator_dst, the octet string representing:
                 "BBS_" || hash_to_curve_suite || "SIG_GENERATOR_DST_",
                 in the ASCII characters encoding.
- seed_len = ceil((ceil(log2(r)) + k)/8), where r and k are defined by
                                          the ciphersuite.

Outputs:

- generators, an array of generators.

Procedure:

1.  v = expand_message(generator_seed, seed_dst, seed_len)
2.  n = 1
3.  for i in range(1, count):
4.     v = expand_message(v || I2OSP(n, 4), seed_dst, seed_len)
5.     n = n + 1
6.     generator_i = Identity_G1
7.     candidate = hash_to_curve_g1(v, generator_dst)
8.     if candidate in (P1, generator_1, ..., generator_i):
9.        go back to step 4
10.    generator_i = candidate
11. return (generator_1, ..., generator_count)
</artwork>
</section>

<section anchor="mapmessagetoscalar"><name>MapMessageToScalar</name>
<t>There are multiple ways in which messages can be mapped to their respective scalar values, which is their required form to be used with the <eref target="#sign">Sign</eref>, <eref target="#verify">Verify</eref>, <eref target="#proofgen">ProofGen</eref> and <eref target="#proofverify">ProofVerify</eref> operations.</t>

<section anchor="mapmessagetoscalarashash"><name>MapMessageToScalarAsHash</name>
<t>This operation takes an input message and maps it to a scalar value via a cryptographic hash function for the given curve.</t>

<artwork>result = MapMessageToScalarAsHash(msg, dst)

Inputs:

- msg (REQUIRED), octet string.
- dst (REQUIRED), octet string. Domain separation tag; note this is not
                  defined as a function argument as per
                  [@!I-D.irtf-cfrg-hash-to-curve] but as a parameter.

Outputs:

- result, a scalar value.

Procedure:

1. If length(dst) &gt; 2^8 - 1 or length(msg) &gt; 2^64 - 1, return INVALID
2. dst_prime = I2OSP(length(dst), 1) || dst
3. msg_prime = I2OSP(length(msg), 8) || msg
4. result = hash_to_scalar(msg_prime || dst_prime, 1)
5. return result
</artwork>
</section>
</section>

<section anchor="hash-to-scalar"><name>Hash to Scalar</name>
<t>This operation describes how to hash an arbitrary octet string to <tt>n</tt> scalar values in the multiplicative group of integers mod r (i.e., values in the range [1, r-1]).  This procedure acts as a helper function, used internally in various places within the operations described in the spec. To map a message to a scalar that would be passed as input to the <eref target="#sign">Sign</eref>, <eref target="#verify">Verify</eref>, <eref target="#proofgen">ProofGen</eref> and <eref target="#proofverify">ProofVerify</eref> functions, one must use <eref target="#mapmessagetoscalar">MapMessageToScalarAsHash</eref> instead.</t>
<t>This operation makes use of expand_message defined in <xref target="I-D.irtf-cfrg-hash-to-curve"/>, in a similar way used by the hash_to_field operation of Section 5 from the same document (with the additional checks for getting a scalar that is 0). Note that, if an implementer wants to use hash_to_field instead, they MUST use the multiplicative group of integers mod r (Fr), as the target group (F). However, the hash_to_curve ciphersuites used by this document, make use of hash_to_field with the target group being the multiplicative group of integers mod p (Fp). For completeness, we define here the operation making use of the expand_message function, that will be defined by the hash-to-curve suite used. If someone also has a hash_to_field implementation available, with the target group been Fr, they can use this instead (adding the check for a scalar been 0).</t>

<artwork>scalars = hash_to_scalar(msg_octets, count)

Inputs:

- msg_octets (REQUIRED), octet string. The message to be hashed.
- count (REQUIRED), an integer greater or equal to 1. The number of
                    scalars to output.

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.

Definitions:

- h2s_dst, the octet string representing the ASCII encoded characters:
           "BBS_" || hash_to_curve_suite || "HASH_TO_SCALAR_".
- expand_len = ceil((ceil(log2(r))+k)/8), where r and k are defined by
                                          the ciphersuite.

Outputs:

- scalars, an array of non-zero scalars mod r.

Procedure:

1.  len_in_bytes = count * expand_len
2.  t = 0
3.  msg_prime = msg_octets || I2OSP(t, 1) || I2OSP(count, 4)
4.  uniform_bytes = expand_message(msg_prime, h2s_dst, len_in_bytes)
5.  for i in (1, ..., count):
6.      tv = uniform_bytes[(i-1)*expand_len..i*expand_len-1]
7.      scalar_i = OS2IP(tv) mod r
8.  if 0 in (scalar_1, ..., scalar_count):
9.      t = t + 1
10.     go back to step 3
11. return (scalar_1, ..., scalar_count)
</artwork>
</section>

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

<section anchor="octetstosignature"><name>OctetsToSignature</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>signature = octets_to_signature(signature_octets)

Inputs:

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

Outputs:

signature, a signature in the form (A, e, s), where A is a point in G1
           and e and s are non-zero scalars mod r.

Procedure:

1.  expected_len = octet_point_length + 2 * 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_g1(A_octets)
5.  if A is INVALID, return INVALID
6.  if A == Identity_G1, return INVALID
7.  index = octet_point_length
8.  end_index = index + octet_scalar_length - 1
9.  e = OS2IP(signature_octets[index..end_index])
10. if e = 0 OR e &gt;= r, return INVALID
11. index += octet_scalar_length
12. end_index = index + octet_scalar_length - 1
13. s = OS2IP(signature_octets[index..end_index])
14. if s = 0 OR s &gt;= r, return INVALID
15. return (A, e, s)
</artwork>
</section>

<section anchor="signaturetooctets"><name>SignatureToOctets</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>, <tt>e</tt> and <tt>s</tt>
because its assumed these are done prior to its invocation, e.g as is the case with the <eref target="#sign">Sign</eref> operation.</t>

<artwork>signature_octets = signature_to_octets(signature)

Inputs:

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

Outputs:

- signature_octets, octet string.

Procedure:

1. (A, e, s) = signature
2. A_octets = point_to_octets_g1(A)
3. e_octets = I2OSP(e, octet_scalar_length)
4. s_octets = I2OSP(s, octet_scalar_length)
5. return (A_octets || e_octets || s_octets)
</artwork>
</section>

<section anchor="octetstoproof"><name>OctetsToProof</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>
<li>Three (3) valid points of the G1 subgroup, each of which must not equal the identity point.</li>
<li>Five (5) 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>
</ol>

<artwork>proof = octets_to_proof(proof_octets)

Inputs:

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

Parameters:

- r (REQUIRED), non-negative integer. The prime order of the G1 and
                G2 groups, defined by the ciphersuite.
- octet_scalar_length (REQUIRED), non-negative integer. The length of
                                  a scalar octet representation, defined
                                  by the ciphersuite.
- octet_point_length (REQUIRED), non-negative integer. The length of
                                 a point in G1 octet representation,
                                 defined by the ciphersuite.

Outputs:

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

Procedure:

1.  proof_len_floor = 3 * octet_point_length + 5 * octet_scalar_length
2.  if length(proof_octets) &lt; proof_len_floor, return INVALID

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

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

16. if index != length(proof_octets), return INVALID
17. msg_commitments = ()
18. If j &gt; 5, set msg_commitments = (s_5, ..., s_(j-1))
19. return (A_0, A_1, A_2, s_0, s_1, s_2, s_3, s_4, msg_commitments)
</artwork>
</section>

<section anchor="prooftooctets"><name>ProofToOctets</name>
<t>This operation describes how to encode a proof, as computed at step 25 in <eref target="#proofgen">ProofGen</eref>, to an octet string. The input to the operation MUST be a valid proof.</t>
<t>The inputed proof value must consist of the following components, in that order:</t>

<ol>
<li>Three (3) valid compressed points of the G1 subgroup, different from the identity point of G1 (i.e., <tt>A', Abar, D</tt>, in ProofGen)</li>
<li>Five (5) integers representing scalars in the range of 1 to r-1 inclusive (i.e., <tt>c, e^, r2^, r3^, s^</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>
</ol>

<artwork>proof_octets = proof_to_octets(proof)

Inputs:

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

Parameters:

- octet_scalar_length (REQUIRED), non-negative integer. The length of
                                  a scalar octet representation, defined
                                  by the ciphersuite.

Outputs:

- proof_octets, octet string.

Procedure:

1. (A', Abar, D, c, e^, r2^, r3^, s^, (m^_1, ..., m^_U)) = proof
2. Let proof_octets be an empty octet string.

// Points Serialization.
3. for point in (A', Abar, D):
4.     point_octets = point_to_octets_g1(point)
5.     proof_octets = proof_octets || point_octets

// Scalar Serialization.
6. for scalar in (c, e^, r2^, r3^, s^, m^_1, ..., m^_U):
7.     scalar_octets = I2OSP(scalar, octet_scalar_length)
8.     proof_octets = proof_octets || scalar_octets
9. return proof_octets
</artwork>
</section>

<section anchor="octetstopublickey"><name>OctetsToPublicKey</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>W = octets_to_pubkey(PK)

Inputs:

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

Outputs:

- W, a valid point in G2 or INVALID

Procedure:

1. W = octets_to_point_g2(PK)
2. If W is INVALID, return INVALID
3. if subgroup_check(W) is INVALID, return INVALID
4. If W == Identity_G2, return INVALID
5. return W
</artwork>
</section>

<section anchor="encodeforhash"><name>EncodeForHash</name>
<t>This document uses the <tt>hash_to_scalar</tt> function to hash elements to scalars in the multiplicative group mod r (see <eref target="#hash-to-scalar">Section 5.3</eref>). To avoid ambiguity, elements passed to that operation, must first be encoded appropriately using <tt>encode_for_hash</tt>. The following procedure describes how to encode each element accordingly by serializing it to an appropriate format depending on its type and concatenating the results. Specifically,</t>

<ul>
<li>Points in G1 or G2 will be encoded using the <tt>point_to_octets_g*</tt> implementation for a particular ciphersuite.</li>
<li>Non-negative integers will be encoded using <tt>I2OSP</tt> with an output length of 8 bytes.</li>
<li>Scalars will be zero-extended to a fixed length, defined by a particular ciphersuite.</li>
<li>Octet strings will be zero-extended to a length that is a multiple of 8 bits. Then, the extended value is encoded directly.</li>
<li>ASCII strings will be transformed into octet strings using UTF-8 encoding.</li>
</ul>
<t>After encoding, octet strings will be prepended with a value representing the length of their binary representation in the form of the number of bytes. This length must be encoded to octets using I2OSP with output length of 8 bytes. The combined value (encoded value + length prefix) binary representation is then encoded as a single octet string. For example, the string <tt>0x14d</tt> will be encoded as <tt>0x0000000000000002014d</tt>. If the length of the octet string is larger than 2^64 - 1, the octet string must be rejected. Similarly, ASCII strings, after encoded to octets (using utf8), will also be appended with the length of their octet-string representation.</t>
<t>Optional input/parameters to operations that feature in a call to hash_to_scalar, that are not supplied to the operation should default to an empty octet string. For example, if X is an optional input/parameter that is not supplied, whilst A and B are required, then the procedural step of <tt>hash(A || X || B)</tt> MUST be evaluated to <tt>hash(A || "" || B)</tt>.</t>
<t>The above is further described in the following procedure.</t>

<artwork>result = encode_for_hash(input_array)

Inputs:

- input_array, an array of elements to be hashed. All elements of this
               array that are octet strings MUST be multiples of 8 bits.

Parameters:

- octet_scalar_length, non-negative integer. The length of a scalar
                       octet representation, defined by the ciphersuite.

Outputs:

- result, an octet string or INVALID.

Procedure:

1.  let octets_to_hash be an empty octet string.
2.  for el in input_array:
3.      if el is an ASCII string: el = utf8(el)
4.      if el is an octet string representing a public key: el_octs = el
5.      else if el is an octet string:
6.          if length(el) &gt; 2^64 - 1, return INVALID
7.          el_octs = I2OSP(length(el), 8) || el
8.      else if el is a Point in G1: el_octs = point_to_octets_g1(el)
9.      else if el is a Point in G2: el_octs = point_to_octets_g2(el)
10.     else if el is a Scalar: el_octs = I2OSP(el, octet_scalar_length)
11.     else if el is a non-negative integer: el_octs = I2OSP(el, 8)
12.     else: return INVALID
13.     octets_to_hash = octets_to_hash || el_octs
14. return octets_to_hash
</artwork>
</section>
</section>
</section>

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

<section anchor="validating-public-keys"><name>Validating public keys</name>
<t>It is RECOMENDED for any operation in <eref target="#core-operations">Core Operations</eref> involving public keys, that they deserialize the public key first using the <eref target="#octetstopublickey">OctetsToPublicKey</eref> operation, even if they only require the octet-string representation of the public key. If the <tt>octets_to_pubkey</tt> procedure (see the <eref target="#octetstopublickey">OctetsToPublicKey</eref> section) returns INVALID, the calling operation should also return INVALID and abort. An example of where this recommendation applies is the <eref target="#sign">Sign</eref> operation. An example of where an explicit invocation to the <tt>octets_to_pubkey</tt> operation is already defined and therefore required is the <eref target="#verify">Verify</eref> operation.</t>
</section>

<section anchor="point-de-serialization"><name>Point de-serialization</name>
<t>This document makes use of <tt>octet_to_point_g*</tt> to parse octet strings to elliptic curve points (either in G1 or G2). It is assumed (even if not explicitly described) that the result of this operation will not be INVALID. If <tt>octet_to_point_g*</tt> returns INVALID, then the calling operation should immediately return INVALID as well and abort the operation. Note that the only place where the output is assumed to be VALID implicitly is in the <eref target="#encodingforhash">EncodingForHash</eref> section.</t>
</section>

<section anchor="skipping-membership-checks"><name>Skipping membership checks</name>
<t>Some existing implementations skip the subgroup_check invocation in <eref target="#verify">Verify</eref>, whose purpose is ensuring that the signature is an element of a prime-order subgroup.  This check is REQUIRED of conforming implementations, for two reasons.</t>

<ol>
<li><t>For most pairing-friendly elliptic curves used in practice, the pairing operation e <xref target="notation"/> is undefined when its input points are not in the prime-order subgroups of E1 and E2. The resulting behavior is unpredictable, and may enable forgeries.</t>
</li>
<li><t>Even if the pairing operation behaves properly on inputs that are outside the correct subgroups, skipping the subgroup check breaks the strong unforgeability property <xref target="ADR02"/>.</t>
</li>
</ol>
</section>

<section anchor="side-channel-attacks"><name>Side channel attacks</name>
<t>Implementations of the signing algorithm SHOULD protect the secret key from side-channel attacks.  One method for protecting against certain side-channel attacks is ensuring that the implementation executes exactly the same sequence of instructions and performs exactly the same memory accesses, for any value of the secret key. In other words, implementations on the underlying pairing-friendly elliptic curve SHOULD run in constant time.</t>
</section>

<section anchor="randomness-considerations"><name>Randomness considerations</name>
<t>The IKM input to KeyGen MUST be infeasible to guess and MUST be kept secret. One possibility is to generate IKM from a trusted source of randomness.  Guidelines on constructing such a source are outside the scope of this document.</t>
<t>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>BBS proofs are nondeterministic, meaning care must be taken against attacks arising from using bad randomness, for example, the nonce reuse attack on ECDSA <xref target="HDWH12"/>. It is RECOMMENDED that the presentation header used in this specification contain a nonce chosen at random from a trusted source of randomness, see the <xref target="presentation-header-selection"/> for additional considerations.</t>
<t>When a trusted source of randomness is used, signatures and proofs are much harder to forge or break due to the use of multiple nonces.</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 presentation header. A verifier-specified cryptographically random value (e.g., a nonce) featuring in the presentation header 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 presentation header 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="I-D.irtf-cfrg-hash-to-curve"/>.</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 curve. However care MUST be taken when selecting one that is appropriate, 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 according to a recent NCC ZCash cryptography review <xref target="ZCASH-REVIEW"/>.</t>
</section>

<section anchor="security-of-proofs-generated-by-proofgen"><name>Security of proofs generated by ProofGen</name>
<t>The proof, as returned by ProofGen, is a zero-knowledge proof-of-knowledge <xref target="CDL16"/>. This guarantees that no information will be revealed about the signature itself or the undisclosed messages, from the output of ProofGen. Note that the security proofs in <xref target="CDL16"/> work on type 3 pairing setting. This means that G1 should be different from G2 and with no efficient isomorphism between them.</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>. The REQUIRED format for this string is</t>

<artwork>  "BBS_" || H2C_SUITE_ID || ADD_INFO
</artwork>

<ul>
<li><t>Strings in double quotes are ASCII-encoded literals.</t>
</li>
<li><t>H2C_SUITE_ID is the suite ID of the hash-to-curve suite used to define the hash<em>to</em>curve function.</t>
</li>
<li><t>ADD_INFO is an optional string indicating any additional information used to uniquely qualify the ciphersuite. When present this value MUST only contain ASCII characters between 0x21 and 0x7e (inclusive), and MUST end with an underscore (0x5f), other than the last character the string MUST not contain any other underscores (0x5f).</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 etc.,), the serialization operations (point_to_octets_g1 etc.,) 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_g*</tt> function. It is RECOMMENDED that this value is set to <tt>ceil(log2(p)/8)</tt>.</t>
</li>
<li><t>hash_to_curve_suite: The hash-to-curve ciphersuite id, in the form defined in <xref target="I-D.irtf-cfrg-hash-to-curve"/>. This defines the hash_to_curve_g1 (the hash_to_curve operation for the G1 subgroup, see the <eref target="#notation">Notation</eref> section) and the expand_message (either expand_message_xmd or expand_message_xof) operations used in this document.</t>
</li>
</ul>
<t><strong>Serialization functions</strong>:</t>

<ul>
<li><t>point_to_octets_g1:
a function that returns the canonical representation of the point P for the G1 subgroup as an octet string.</t>
</li>
<li><t>point_to_octets_g2:
a function that returns the canonical representation of the point P for the G2 subgroup as an octet string.</t>
</li>
<li><t>octets_to_point_g1:
a function that returns the point P in the subgroup G1 corresponding to the canonical representation ostr, or INVALID if ostr is not a valid output of <tt>point_to_octets_g1</tt>.</t>
</li>
<li><t>octets_to_point_g2:
a function that returns the point P in the subgroup G2 corresponding to the canonical representation ostr, or INVALID if ostr is not a valid output of <tt>point_to_octets_g2</tt>.</t>
</li>
</ul>
<t><strong>Generator parameters</strong>:</t>

<ul>
<li>generator_seed: The seed used to determine the generator points which form part of the public parameters used by the BBS signature scheme. Note there are multiple possible scopes for this seed, including: a globally shared seed (where the resulting message generators are common across all BBS signatures); a signer specific seed (where the message generators are specific to a signer); and a signature specific seed (where the message generators are specific per signature). The ciphersuite MUST define this seed OR how to compute it as a pre-cursor operation to any others.</li>
</ul>
</section>
</section>

<section anchor="bls12-381-ciphersuite"><name>BLS12-381 Ciphersuite</name>
<t>The following ciphersuite is based on the BLS12-381 elliptic curve defined in Section 4.2.1 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/>. The targeted security level of the suite in bits is <tt>k = 128</tt>. The ciphersuite makes use of an extendable output function, and most specifically of SHAKE-256, as defined in Section 6.2 of <xref target="SHA3"/>. It also uses the hash-to-curve suite defined by this document in <eref target="#bls12-381-hash_to_curve-def">Appendix A.1</eref>, which also makes use of the SHAKE-256 function.</t>
<t><strong>Basic parameters</strong>:</t>

<ul>
<li><t>Ciphersuite_ID: "BBS_BLS12381G1_XOF:SHAKE-256_SSWU_RO_"</t>
</li>
<li><t>hash: SHAKE-256 as defined in <xref target="SHA3"/>.</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_R0_" as defined in <eref target="#bls12-381-hash-to-curve-definition-using-shake-256">Appendix A.1</eref> for the G1 subgroup.</t>
</li>
</ul>
<t><strong>Serialization functions</strong>:</t>

<ul>
<li><t>point_to_octets_g1: follows the format documented in Appendix C section 1 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/> for the G1 subgroup, using compression (i.e., setting C_bit = 1).</t>
</li>
<li><t>point_to_octets_g2: follows the format documented in Appendix C section 1 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/> for the G2 subgroup, using compression (i.e., setting C_bit = 1).</t>
</li>
<li><t>octets_to_point_g1: follows the format documented in Appendix C section 2 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/> for the G1 subgroup.</t>
</li>
<li><t>octets_to_point_g2: follows the format documented in Appendix C section 2 of <xref target="I-D.irtf-cfrg-pairing-friendly-curves"/> for the G2 subgroup.</t>
</li>
</ul>
<t><strong>Generator parameters</strong>:</t>

<ul>
<li>generator_seed: A global seed value of "BBS_BLS12381G1_XOF:SHAKE-256_SSWU_RO_MESSAGE_GENERATOR_SEED" which is used by the <eref target="#generator-point-computation">create_generators</eref> operation to compute the required set of message generators.</li>
</ul>

<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 implementations correctness</t>
<t><strong>NOTE</strong> All binary data below is represented as octet strings encoded in hexadecimal format</t>
<t><strong>NOTE</strong> These fixtures are a work in progress and subject to change</t>
<t>Further fixtures are available in <xref target="additional-bls12-381-ciphersuite-test-vectors"/></t>

<section anchor="message-generators"><name>Message Generators</name>
<t>Following the procedure defined in <xref target="generator-point-computation"/> with an input seed value of</t>

<artwork>BBS_BLS12381G1_XOF:SHAKE-256_SSWU_RO_MESSAGE_GENERATOR_SEED
</artwork>
<t>a dst of</t>

<artwork>BBS_BLS12381G1_XOF:SHAKE-256_SSWU_RO_
</artwork>
<t>and a length value of <tt>10</tt></t>
<t>Outputs the following values</t>

<artwork>{{ $generators[0] }}

{{ $generators[1] }}

{{ $generators[2] }}

{{ $generators[3] }}

{{ $generators[4] }}

{{ $generators[5] }}

{{ $generators[6] }}

{{ $generators[7] }}

{{ $generators[8] }}

{{ $generators[9] }}
</artwork>
</section>

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

<artwork>{{ $keyPair.seed }}
</artwork>
<t>Outputs the following SK value</t>

<artwork>{{ $keyPair.keyPair.secretKey }}
</artwork>
<t>Following the procedure defined in <xref target="sktopk"/> with an input SK value as above produces the following PK value</t>

<artwork>{{ $keyPair.keyPair.publicKey }}
</artwork>
</section>

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

<artwork>{{ $signatureFixtures.signature001.messages[0] }}
</artwork>
<t>Along with the SK value as defined in <xref target="key-pair"/> as inputs into the Sign operations, yields the following output signature</t>

<artwork>{{ $signatureFixtures.signature001.signature }}
</artwork>
</section>

<section anchor="valid-multi-message-signature"><name>Valid Multi-Message Signature</name>
<t>Using the following messages (<strong>Note</strong> the ordering of the messages MUST be preserved)</t>

<artwork>{{ $signatureFixtures.signature004.messages[0] }}

{{ $signatureFixtures.signature004.messages[1] }}

{{ $signatureFixtures.signature004.messages[2] }}

{{ $signatureFixtures.signature004.messages[3] }}

{{ $signatureFixtures.signature004.messages[4] }}

{{ $signatureFixtures.signature004.messages[5] }}

{{ $signatureFixtures.signature004.messages[6] }}

{{ $signatureFixtures.signature004.messages[7] }}

{{ $signatureFixtures.signature004.messages[8] }}

{{ $signatureFixtures.signature004.messages[9] }}
</artwork>
<t>Along with the SK value as defined in <xref target="key-pair"/> as inputs into the Sign operations, yields the following output signature</t>

<artwork>{{ $signatureFixtures.signature004.signature }}
</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 preceeded the development of this document. In particular the original work of <xref target="BBS04"/> which was subsequently developed in <xref target="ASM06"/> and in <xref target="CDL16"/>. 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 and Tomislav Markovski</t>
</section>

</middle>

<back>
<references><name>Normative References</name>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml-ids/reference.I-D.irtf-cfrg-hash-to-curve.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml-ids/reference.I-D.irtf-cfrg-pairing-friendly-curves.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.4868.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5869.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.8017.xml"/>
<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>
    <date/>
  </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="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="Springer," value="Berlin, Heidelberg"/>
</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="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="Springer," value="Cham"/>
</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="pages" value="205-220"/>
</reference>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml-ids/reference.I-D.irtf-cfrg-bls-signature.xml"/>
<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>
    <date/>
  </front>
</reference>
</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="I-D.irtf-cfrg-hash-to-curve"/> 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="I-D.irtf-cfrg-hash-to-curve"/>.</t>
<t>Note the notation used in the below definitions is sourced from <xref target="I-D.irtf-cfrg-hash-to-curve"/>.</t>

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

<artwork>* encoding type: hash_to_curve (Section 3 of
                 [@!I-D.irtf-cfrg-hash-to-curve])

* 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
                  [@!I-D.irtf-cfrg-hash-to-curve])

* hash: SHAKE-256

* L: 64

* f: Simplified SWU for AB == 0 (Section 6.6.3 of
     [@!I-D.irtf-cfrg-hash-to-curve])

* 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
            [@!I-D.irtf-cfrg-hash-to-curve]

*  h_eff: 0xd201000000010001
</artwork>
<t>Note that the h_eff 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="I-D.irtf-cfrg-hash-to-curve"/>.</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="I-D.irtf-cfrg-hash-to-curve"/>.</t>
</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 <eref target="https://json-web-proofs.github.io/json-web-proofs/draft-jmiller-json-web-proof.html">JWP</eref> format and serialization). 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 (<eref target="https://datatracker.ietf.org/doc/html/draft-ietf-oauth-dpop-04">https://datatracker.ietf.org/doc/html/draft-ietf-oauth-dpop-04</eref>) 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 ofter 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 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-bls12-381-ciphersuite-test-vectors"><name>Additional BLS12-381 Ciphersuite Test Vectors</name>
<t><strong>NOTE</strong> These fixtures are a work in progress and subject to change</t>

<section anchor="modified-message-signature"><name>Modified Message Signature</name>
<t>Using the following message</t>

<artwork>{{ $signatureFixtures.signature002.messages[0] }}
</artwork>
<t>And the following signature</t>

<artwork>{{ $signatureFixtures.signature002.signature }}
</artwork>
<t>Along with the PK value as defined in <xref target="key-pair"/> as inputs into the Verify operation should fail signature validation due to the message value being different from what was signed</t>
</section>

<section anchor="extra-unsigned-message-signature"><name>Extra Unsigned Message Signature</name>
<t>Using the following messages</t>

<artwork>{{ $signatureFixtures.signature003.messages[0] }}

{{ $signatureFixtures.signature003.messages[1] }}
</artwork>
<t>And the following signature</t>

<artwork>{{ $signatureFixtures.signature002.signature }}
</artwork>
<t>Along with the PK value as defined in <xref target="key-pair"/> as inputs into the Verify operation should fail signature validation due to an additional message being supplied that was not signed</t>
</section>

<section anchor="missing-message-signature"><name>Missing Message Signature</name>
<t>Using the following messages</t>

<artwork>{{ $signatureFixtures.signature005.messages[0] }}

{{ $signatureFixtures.signature005.messages[1] }}
</artwork>
<t>And the following signature</t>

<artwork>{{ $signatureFixtures.signature005.signature }}
</artwork>
<t>Along with the PK value as defined in <xref target="key-pair"/> as inputs into the Verify operation should fail signature validation due to missing messages that were originally present during the signing</t>
</section>

<section anchor="reordered-message-signature"><name>Reordered Message Signature</name>
<t>Using the following messages</t>

<artwork>{{ $signatureFixtures.signature006.messages[0] }}

{{ $signatureFixtures.signature006.messages[1] }}

{{ $signatureFixtures.signature006.messages[2] }}

{{ $signatureFixtures.signature006.messages[3] }}

{{ $signatureFixtures.signature006.messages[4] }}

{{ $signatureFixtures.signature006.messages[5] }}

{{ $signatureFixtures.signature006.messages[6] }}

{{ $signatureFixtures.signature006.messages[7] }}

{{ $signatureFixtures.signature006.messages[8] }}

{{ $signatureFixtures.signature006.messages[9] }}
</artwork>
<t>And the following signature</t>

<artwork>{{ $signatureFixtures.signature006.signature }}
</artwork>
<t>Along with the PK value as defined in <xref target="key-pair"/> as inputs into the Verify operation should fail signature validation due to messages being re-ordered from the order in which they were signed</t>
</section>

<section anchor="wrong-public-key-signature"><name>Wrong Public Key Signature</name>
<t>Using the following messages</t>

<artwork>{{ $signatureFixtures.signature007.messages[0] }}

{{ $signatureFixtures.signature007.messages[1] }}

{{ $signatureFixtures.signature007.messages[2] }}

{{ $signatureFixtures.signature007.messages[3] }}

{{ $signatureFixtures.signature007.messages[4] }}

{{ $signatureFixtures.signature007.messages[5] }}

{{ $signatureFixtures.signature007.messages[6] }}

{{ $signatureFixtures.signature007.messages[7] }}

{{ $signatureFixtures.signature007.messages[8] }}

{{ $signatureFixtures.signature007.messages[9] }}
</artwork>
<t>And the following signature</t>

<artwork>{{ $signatureFixtures.signature007.signature }}
</artwork>
<t>Along with the PK value as defined in <xref target="key-pair"/> as inputs into the Verify operation should fail signature validation due to public key used to verify is in-correct</t>
</section>
</section>

<section anchor="proof-generation-and-verification-algorithmic-explanation"><name>Proof Generation and Verification Algorithmic Explanation</name>
<t>The following section provides an explanation of how the ProofGen and ProofVerify operations work.</t>
<t>Let the prover be in possession of a BBS signature <tt>(A, e, s)</tt> on messages <tt>msg_1, ..., msg_L</tt> and a <tt>domain</tt> value (see <eref target="#sign">Sign</eref>). Let <tt>A = B * (1/(e + SK))</tt> where <tt>SK</tt> the signer's secret key and,</t>

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

<ul>
<li><t>Hide the signature by randomizing it. To randomize the signature <tt>(A, e, s)</tt>, take uniformly random <tt>r1</tt>, <tt>r2</tt> in <tt>[1, r-1]</tt>, and calculate,</t>

<artwork>1.  A' = A * r1,
2.  Abar = A' * (-e) + B * r1
3.  D = B * r1 + H0 * r2.
</artwork>
<t>Also set,</t>

<artwork>4.  r3 = r1 ^ -1 mod r
5.  s' = r2 * r3 + s mod r.
</artwork>
<t>The values <tt>(A', Abar, D)</tt> will be part of the proof and are used to prove possession of a BBS signature, without revealing the signature itself. Note that; <tt>e(A', PK) = e(Abar, P2)</tt> where <tt>PK</tt> the signer's public key and <tt>P2</tt> the base element in <tt>G2</tt> (used to create the signer’s <tt>PK</tt>, see <eref target="#sktopk">SkToPk</eref>). This also serves to bind the proof to the signer's <tt>PK</tt>.</t>
</li>
<li><t>Set the following,</t>

<artwork>1.  C1 = Abar - D
2.  C2 = P1 + Q_2 * domain + H_i1 * msg_i1 + ... + H_iR * msg_iR
</artwork>
<t>Create a non-interactive zero-knowledge proof-of-knowledge (<tt>nizk</tt>) of the values <tt>e, r2, r3, s'</tt> and <tt>msg_j1, ..., msg_jU</tt> (the undisclosed messages) so that both of the following equalities hold,</t>

<artwork>EQ1.  C1 = A' * (-e) - H0 * r2
EQ2.  C2 = H0 * s' - D * r3 + H_j1 * msg_j1 + ... + H_jU * msg_jU.
</artwork>
</li>
</ul>
<t>Note that the verifier will know the elements in the left side of the above equations (i.e., <tt>C1</tt> and <tt>C2</tt>) but not in the right side (i.e., <tt>s'</tt>, <tt>r3</tt> and the undisclosed messages: <tt>msg_j1, ..., msg_jU</tt>). However, using the <tt>nizk</tt>, the prover can convince the verifier that they (the prover) know the elements that satisfy those equations, without disclosing them. Then, if both EQ1 and EQ2 hold, and <tt>e(A', PK) = e(Abar, P2)</tt>, an extractor can return a valid BBS signature from the signer's <tt>SK</tt>, on the disclosed messages. The proof returned is <tt>(A', Abar, D, nizk)</tt>. To validate the proof, a verifier checks that <tt>e(A', PK) = e(Abar, P2)</tt> and verifies the <tt>nizk</tt>. Validating the proof, will guarantee the authenticity and integrity of the disclosed messages, as well as ownership of the undisclosed messages and of the signature.</t>
</section>

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

<ul>
<li>Initial version</li>
</ul>
</section>

</back>

</rfc>
