- SK
- The secret key for the signature scheme.
- PK
- The public key for the signature scheme.
- message
- An octet string, representing a signed message.
- L
- The total number of signed messages.
- R
- The number of message indexes that are disclosed (revealed) in a proof-of-knowledge of a signature.
- U
- The number of message indexes that are undisclosed in a proof-of-knowledge of a signature.
- scalar
- An integer between 0 and r-1, where r is the prime order of the selected groups, defined by each ciphersuite (see also
). - generator
- A valid point on the selected subgroup of the curve being used that is employed to commit a value.
- signature
- The digital signature output.
- header
- A payload chosen by the Signer and bound to a BBS signature, as well as the BBS proofs generated using that signature.
- presentation_header (ph)
- A payload generated and bound to a specific BBS proof.
- dst
- The domain separation tag.
- I2OSP
- An operation that transforms a non-negative integer into an octet string, defined in Section 4 of
. Note, the output of this operation is in big-endian order. - OS2IP
- An operation that transforms a octet string into an non-negative integer, defined in Section 4 of
. Note, the input of this operation must be in big-endian order. - INVALID, ABORT
- 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.

- a || b
- Denotes the concatenation of octet strings a and b.
- I \ J
- 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.
- X[a..b]
- Denotes a slice of the array
`X`containing all elements from and including the value at index`a`until and including the value at index`b`. Note when this syntax is applied to an octet string, each element in the array`X`is assumed to be a single byte. - length(input)
- 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.
- X[i]
- Denotes the element of array
`X`at index`i`. Note that arrays in this document are considered "zero-indexed", meaning that element indexing starts from 0 rather than 1. For example, if`X = [a, b, c, d]`then`X[0] = a`,`X[1] = b`,`X[2] = c`and`X[3] = d`.

- E1, E2
- 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 x * P denotes scalar multiplication.
- G1, G2
- subgroups of E1 and E2 (respectively) having prime order r.
- GT
- a subgroup, of prime order r, of the multiplicative group of a field extension.
- h
- G1 x G2 -> GT: a non-degenerate bilinear map.
- r
- The prime order of the G1 and G2 subgroups.
- BP1, BP2
- base (constant) points on the G1 and G2 subgroups respectively.
- Identity_G1, Identity_G2, Identity_GT
- The identity element for the G1, G2, and GT subgroups respectively.
- hash_to_curve_g1(ostr, dst) -> P
- 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
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). - point_to_octets_E1(P) -> ostr, point_to_octets_E2(P) -> ostr
- 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.
- octets_to_point_E1(ostr) -> P, octets_to_point_E2(ostr) -> P
- 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.
- subgroup_check_G1(P), subgroup_check_G2(P) -> VALID or INVALID
- 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.,
. Note that these functions should always return VALID, on input the Identity point of the corresponding subgroup.

Scheme Definition ( ), defines the core operations and parameters for the BBS signature scheme. Utility Operations ( ), defines utilities used by the BBS signature scheme. Security Considerations ( ), describes a set of security considerations associated to the signature scheme. Ciphersuites ( ), defines the format of a ciphersuite, alongside a concrete ciphersuite based on the BLS12-381 curve.

A pairing-friendly elliptic curve, plus associated functionality given in . A hash-to-curve suite as defined in , using the aforementioned pairing-friendly curve. This defines the hash_to_curve and expand_message operations, used by this document. 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 for recommendations and requirements on the generation of random numbers. subgroup_check_G1(P) and subgroup_check_G2(P): operations that return VALID if the point P is in the subgroup G1 or G2 correspondingly, and INVALID otherwise, as defined in .

- A set of low level (core) operations, taking care of the main cryptographic functionality.
- An Application Interface, that uses the core operations in a secure way.

- Create the necessary generators.
- Map the inputted messages to scalars.

- Points in
`E*`will be serialized using the`point_to_octets_E*`implementation for a particular ciphersuite. - Non-negative integers will be serialized using
`I2OSP`with an output length of 8 bytes. - Scalars will be serialized using
`I2OSP`with a constant output length defined by a particular ciphersuite.

`hash_to_scalar`is defined in`calculate_domain`is defined in. `serialize`,`signature_to_octets`,`octets_to_signature`,`proof_to_octets`,`octets_to_proof`and`octets_to_pubkey`are defined in. `h`is the pairing operation used (see), defined as part of the ciphersuite.

- The total number of disclosed messages
`R`. - Each index in the
`disclosed_indexes`list, followed by the corresponding disclosed message (i.e., if`disclosed_indexes = [i1, i2]`and`disclosed_messages = [msg_i1, msg_i2]`, the input to the challenge digest, after`R`, will include`i1 || msg_i1 || i2 || msg_i2`). - The points
`Abar, Bbar, D, T1, T2`and the`domain`scalar, calculated during the proof initialization phase of`CoreProofGen`(see). - The inputted presentation header (
`ph`) values.

- The generators should be indistinguishable from uniformly radom points of G1 (even given the knowledge of the system's public parameters, like the
`generator_seed`value in). This means that given only the points `H_1, ..., H_i`it should be infeasible to guess`H_(i+1)`(or any`H_j`with`j > i`), for any`i`. This also means that it should be infeasible to represent any of the generators as multi-exponentiation product (i.e., of the form`H_i1 * a_1 + H_i2 * a_2 + ... + H_in * a_n`) of any of the other generators. - 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
`k`, the probability of a collision should be at most`1/2^k`. - The returned points must be different from the Identity point of G1 as well as the constant point
`P1`defined by the ciphersuite.

- It MUST be deterministic and constant time for a specific number of generators.
- It MUST use proper domain separation for both the
`create_generators`procedure, as well as all of the internally-called procedures.

- 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.
- Unique inputs MUST result in unique outputs.
- If the inputted vector of messages does not include any duplicates, the outputted scalars MUST NOT include any duplicates either.
- It MUST be deterministic and constant time on the length of the inputted vector of messages.

- Three (3) valid points of the G1 subgroup, different from the identity point of G1 (i.e.,
`Abar, Bbar, D`, in ProofGen) - Three (3) integers representing scalars in the range of 1 to r - 1 inclusive (i.e.,
`e^, r1^, r3^`, in ProofGen). - 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.,
`m^_j1, ..., m^_jU`, in ProofGen, where U the number of undisclosed messages). - One (1) integer representing a scalar in the range 1 to r-1 inclusive (i.e.,
`c`in ProofGen).

- Three (3) valid points of the G1 subgroup, each of which must not equal the identity point.
- Three (3) integers representing scalars in the range of 1 to r - 1 inclusive.
- 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., "()").
- One (1) integer representing a scalar in the range of 1 to r - 1 inclusive, corresponding to the proof's challenge (
`c`).

H2C_SUITE_ID is the suite ID of the hash-to-curve suite used to define the hash_to_curve function. 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.

hash: a cryptographic hash function. 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 `ceil(log2(r)/8)`.octet_point_length: Number of bytes to represent a point encoded as an octet string outputted by the `point_to_octets_E*`function.hash_to_curve_suite: The hash-to-curve ciphersuite id, in the form defined in . This defines the hash_to_curve_g1 (the hash_to_curve operation for the G1 subgroup, see the Notation defined in ) and the expand_message (either expand_message_xmd or expand_message_xof) operations used in this document. expand_len: Must be defined to be at least `ceil((ceil(log2(r))+k)/8)`, where`log2(r)`and`k`are defined by each ciphersuite (see Section 5 infor a more detailed explanation of this definition). P1: A fixed point in the G1 subgroup, different from the point BP1 (i.e., the base point of G1, see ). 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 ). h: The pairing operation used.

point_to_octets_E1: a function that returns the canonical representation of the point P of the E1 elliptic curve as an octet string. point_to_octets_E2: a function that returns the canonical representation of the point P of the E2 elliptic curve as an octet string. 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 `point_to_octets_E1`.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 `point_to_octets_E2`.

ciphersuite_id: "BBS_BLS12381G1_XOF:SHAKE-256_SSWU_RO_" octet_scalar_length: 32, based on the RECOMMENDED approach of `ceil(log2(r)/8)`.octet_point_length: 48, based on the RECOMMENDED approach of `ceil(log2(p)/8)`.hash_to_curve_suite: "BLS12381G1_XOF:SHAKE-256_SSWU_RO_" as defined in Appendix A.1 for the G1 subgroup.expand_len: 48 ( `= ceil((ceil(log2(r))+k)/8)`)P1: the following point of G1, serialized using the point_to_octets_E1 procedure defined by this ciphersuite and hex encoded P1 = "8929dfbc7e6642c4ed9cba0856e493f8b9d7d5fcb0c31ef8fdcd34d50648a5 6c795e106e9eada6e0bda386b414150755" h: the optimal Ate pairing (Appendix A.2 of ), defined in .

point_to_octets_E1: as defined in for points of the curve `E1`(which follows the format documented in Appendix C.1 offor the `E1`elliptic curve, using compression).point_to_octets_E2: as defined in for points of the curve `E2`(which follows the format documented in Appendix C.1 offor the `E2`elliptic curve, using compression).octets_to_point_E1: as defined in (which follows the format documented in Appendix C.2 of ), returning INVALID if the resulting point is not in `E1`.octets_to_point_E2: as defined in (which follows the format documented in Appendix C.2 of ), returning INVALID if the resulting point is not in `E2`.

Ciphersuite_ID: "BBS_BLS12381G1_XMD:SHA-256_SSWU_RO_" octet_scalar_length: 32, based on the RECOMMENDED approach of `ceil(log2(r)/8)`.octet_point_length: 48, based on the RECOMMENDED approach of `ceil(log2(p)/8)`.hash_to_curve_suite: "BLS12381G1_XMD:SHA-256_SSWU_RO_" as defined in Section 8.8.1 of the for the G1 subgroup. expand_len: 48 ( `= ceil((ceil(log2(r))+k)/8)`)P1: the following point of G1, serialized using the point_to_octets_E1 procedure defined by this ciphersuite and hex encoded P1 = "a8ce256102840821a3e94ea9025e4662b205762f9776b3a766c872b948f1fd 225e7c59698588e70d11406d161b4e28c9" h: the optimal Ate pairing (Appendix A.2 of ), defined in .

point_to_octets_E1: as defined in for points of the curve `E1`(which follows the format documented in Appendix C.1 offor the `E1`elliptic curve, using compression).point_to_octets_E2: as defined in for points of the curve `E2`(which follows the format documented in Appendix C.1 offor the `E2`elliptic curve, using compression).octets_to_point_E1: as defined in (which follows the format documented in Appendix C.2 of ), returning INVALID if the resulting point is not in `E1`.octets_to_point_E2: as defined in (which follows the format documented in Appendix C.2 of ), returning INVALID if the resulting point is not in `E2`.

- For an octet string
`x`,`x[0]`will denote the first octet (i.e., 8 most significant bits) of`x`. - On input an element
`y`of`GF(p)`or`GF(p^2)`,`sqrt(y)`will return the square root of that element in the respective group, i.e., an element`a`such that`a^2 = y`, or INVALID. - For clarity, we will use
`Identity_E1`,`Identity_E2`to denote the identity points of`E1`and`E2`correspondingly (note that`Identity_E1`is the same point as`Identity_G1`and`Identity_E2`is the same point as`Identity_G2`).

`C_bit`is set to 1 (indicating that point compression is used).`I_bit`is 1 if`P`is either the`Identity_E1`or`Identity_E2`points, otherwise it is 0.`S_bit`is 0 if`I_bit`is 1 (again note that the ciphersuites described in this document always use point compression). Otherwise (i.e., when point compression is used and`P`is not the identity point of its respective curve), if`P`is a point on`E1`, set`S_bit = sign_GF_p(y)`, else if`P`is a point on`E2`,`S_bit = sign_GF_p^2(y)`.

- If
`P = Identity_E1`, set`x_string = I2OSP(0, 48)`. - If
`P`is a point on`E1`and`P != Identity_E1`, set`x_string = I2OSP(x, 48)`. - If
`P = Identity_E2`, set`x_string = I2OSP(0, 96)`. - If
`P`is a point on`E2`and`P != Identity_E2`, then let`x_0`and`x_1`elements of`GF(p)`such that`x = (x_0, x_1)`and set`x_string = I2OSP(x_1, 48) || I2OSP(x_0, 48)`.

Determine the curve of the encoded point as follows, - If
`s_string`has length 48 octets, the encoded point is on the curve`E1`. - If
`s_string`has length 96 octets, the encoded point is on the curve`E2`. - If
`s_string`has any other length, output INVALID and abort the operation.

- If
Let `s_string[0] = s_string[0] AND 0x1F`, where`AND`is computed bitwise (this will set the three most significant bits of`s_string[0]`to 0).If `I_bit`is 1, then the encoded point must be the Identity point of the curve determined on step 1. If`s_string`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`Identity_E1`or`Identity_E2`).Let `x = OS2IP(s_string)`.If the curve that was determined in step 1 is `E1`,- Let
`y2 = x^3 + 4`in`GF(p)`. - If
`y2`is not square in`GF(p)`, output INVALID and abort the operation. Otherwise, let`y = sqrt(y2)`in`GF(p)`and set`Y_bit = sign_GF_p(y)`.

- Let
If the curve that was determined in step 1 is `E2`,- Let
`y2 = x^3 + 4 * (I + 1)`in`GF(p^2)`. - If
`y2`is not square in`GF(p^2)`, output INVALID and abort the operation. Otherwise, let`y = sqrt(y2)`in`GF(p^2)`and set`Y_bit = sign_GF_p^2(y)`.

- Let
If `S_bit`equals`Y_bit`, output`P = (x, y)`. Otherwise, output`P = (x, -y)`.

Prove possession of a valid signature. As defined above, a signature `(A, e)`, on messages`msg_1, ..., msg_L`is valid if`A = B * 1/(e + SK)`, where`B`as in [1]. However, the Prover cannot reveal neither`A`,`e`nor`B`to the Verifier (signature is uniquely identifiable and`B`will reveal information about the signed messages, even the undisclosed ones). To get around this, the Prover needs to hide the signature`(A, e)`and the value of`B`, in a way that will allow proving knowledge of such elements with the aforementioned relationship (i.e., that`A = B * 1/(e + SK)`), without revealing their value. The Prover will do this by randomizing them. To do that, they take uniformly random`r1, r2`in`[1, r-1]`, and calculate,[2] Abar = A * (r1 * r2) [3] D = B * r2 [4] Bbar = D * r1 + Abar * (-e) The values `(Abar, D, Bbar)`will be part of the proof and are used to prove possession of a BBS signature, without revealing the signature itself. Note that; if`Abar`and`Bbar`are constructed using a valid BBS signature as above, then`Abar * SK = Bbar`which is equivalent to`h(Abar, PK) = h(Bbar, BP2)`, where`SK`,`PK`the Signer's secret and public key and`BP2`the base generator of`G2`(used to create the Signer's`PK`, see). This last equation is something that the Verifier can check using the Signer's `PK`.Prove that the disclosed messages are signed as part of that signature. The Prover will start by setting the following, [5] r2' = (1 / r2) mod r If the `Abar`,`D`and`Bbar`values are constructed using a valid BBS signature as in [2], [3] and [4], then the following will hold,[6] P1 + Q_1 * domain + H_i1 * msg_i1 + ... + H_iR * msg_iR = D * r2' - H_ji * msg_j1 - ... - H_jU * msg_jU

- Initial version

- Populated fixtures
- Added SHA-256 based ciphersuite
- Fixed typo in ProofVerify
- Clarify ASCII string usage in DST
- Added MapMessageToScalar test vectors
- Fix typo in ciphersuite name

- Variety of editiorial clarifications
- Clarified integer endianness
- Revised the encode for hash operation
- Shifted to using CSPRNG instead of PRF
- Removed total number of messages from proof verify operation
- Added deterministic proof fixtures
- Shifted to multiple CSPRNG calls to calculate random elements, instead of expand_message
- Updated hash_to_scalar to a single output

- Updated core operation based on new
academic paper - Variety of editorial updates
- Updated exception and error handling
- Added extension point for the operation with which the generators are created, allowing ciphersuites to define different operations for creating the generator points.
- 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
- Added signature/proof fixtures with an empty header or an empty presentation header input
- Updated the fixtures to use variable length messages (one of which is now the empty message "")

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

- Proof Generation and Verification operations updated based on Appendix B of
. - Test vectors updated based on the new proof generation procedure.
- Removed the optional
`commitment`value from the`CoreSign`operation, as the intended use case (blind signatures) will be addressed differently and in another document. - Changed the reference to
from Normative to Informative, by re-defining the relevant functionality to this document. - Various editorial updates.

- To support bounded memory implementations, the order of the inputs to the digest operation for the calculation of the
`e`value during`CoreSign`and the`challenge`value during`CoreProofGen`and`CoreProofVerify`was updated. - Updated the test vectores to match the above update.
- Renamed the pairing function from
`e`to`h`, to avoid naming collisions with the scalar component of the signature. - Renamed
`signature_dst`,`challenge_dst`and`domain_dst`to`hash_to_scalar_dst`.