Module BBS

BBS signature scheme

The BBS signature scheme (also known as the Boneh-Boyen-Shacham signature scheme) is a cryptographic signature scheme based on pairing-based cryptography: the BBS scheme is particularly notable for its use of bilinear pairings on elliptic curves, which enable efficient verification and compact signatures.

It is a probabilistic digital signature scheme based on the discrete logarithm problem, i.e. the difficult of finding the dicrete logarithm in a gruop of prime order.

The BBS signature scheme utilizes two elliptic curves in its construction: E1: y ^ 2 = x ^ 3 + 4 defined over the finite field GF(p).

E2: y ^ 2 = x ^ 3 + 4 * (I + 1) where I ^ 2 + 1 = 0 defined over the finite field GF(p^2)

where p = (t - 1)^2 * (t^4 - t^2 + 1) / 3 + t and t = -2^63 - 2^62 - 2^60 - 2^57 - 2^48 - 2^16.

Let be observed that p is not a prime number and the two subgroups G1 and G2 of E1 and E2 are the two groups used for the pairing having the same order r = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 which is a prime factor of p.

Public keys and key generation are considered as points in G2 and signatures as point in G1. This choice allows to provide short signatures with strong security guarantees.

Functions

ciphersuite (hash) Return a specific ciphersuite based on the provided hash name.
keygen (ciphersuite, key_material, key_info, key_dst) Generate a secret key (sk) for use in cryptographic operations.
hash_to_field_m1_c2 (ciphersuite, msg, dst) Hash a message into two field elements in the prime field of an elliptic curve.
hash_to_curve (ciphersuite, msg, dst) Hash a message to a point on an elliptic curve.
create_generators (ciphersuite, count) Create a set of cryptographic generators.
messages_to_scalars (ciphersuite, messages) Convert a list of messages, a vector of octets, into a list of scalar values using a cryptographic hash function.
sign (ciphersuite, sk, header, messages) The Sign operation returns a BBS signature from a secret key (sk), over a header and a set of messages.
octets_to_pub_key (pk) Ensure that the public key is valid, in the right subgroup, and not the identity element.
verify (ciphersuite, pk, signature, header, messages) Validate a BBS signature.
calculate_random_scalars (count) Generate a table of random scalars that are uniformly distributed modulo the ECP order.
proof_gen (ciphersuite, pk, signature, header, ph, messages, indexes) Allow a user to prove knowledge of a valid signature while selectively revealing some messages and keeping others hidden.
proof_verify (ciphersuite, pk, header, ph, messages, indexes) It is responsible for validating a BBS proof.


Functions

ciphersuite (hash)
Return a specific ciphersuite based on the provided hash name.
There are two possibilities for the output: the configuration for SHAKE-256 or the configuration for SHA-256.

Parameters:

  • hash a string with the name of the hash function, sha256 or shake256

Returns:

    a ciphersuite configuration

Usage:

    bbs = require'crypto_bbs'
    **select the hash sha256
    suite = bbs.ciphersuite('sha256')
    **print for example the ciphersuite ID
    print(suite.ciphersuite_ID)
    **print: BBS_BLS12381G1_XMD:SHA-256_SSWU_RO_
keygen (ciphersuite, key_material, key_info, key_dst)
Generate a secret key (sk) for use in cryptographic operations.
The function uses a provided ciphersuite, key material, key info, and domain separation tag (DST) to derive the secret key. The ciphersuite is a table containing the cipher suite configuration. Key material is an optional input used as the seed for key generation. If not provided, a secure random value of 32 bytes is generated. Key info is an optional addition information. If not provided, it defaults to an empty octet. key DST is an optional domain separation tag. If not provided, it defaults to the ciphersuite's ciphersuite_ID concatenated with the string 'KEYGEN_DST_'.

Parameters:

  • ciphersuite
  • key_material
  • key_info
  • key_dst

Returns:

    sk, a private key 32 bytes long

Usage:

    bbs = require'crypto_bbs'
    **generate ciphersuite and  key_m, key_info, key_dst as random octet of 32 bytes
    ciphersuite = bbs.ciphersuite('sha256')
    key_material = O.random(32)
    key_info = O.random(32)
    key_dst = O.randopm(32)
    **calculate the private key
    sk = bbs.keygen(ciphersuite, key_material, key_info, key_dst)
hash_to_field_m1_c2 (ciphersuite, msg, dst)
Hash a message into two field elements in the prime field of an elliptic curve. This is a common operation in cryptographic protocols,
where messages need to be mapped to field elements. The third input of the function, the domain separation tag, ensures that the same input message can be hashed differently for different purposes, preventing collisions or unintended reuse of hash outputs.

Parameters:

  • ciphersuite
  • msg the input message to be hashed
  • dst a domain separation tag

Returns:

    a table containing the two field elements

Usage:

    bbs = require'crypto_bbs'
    **define a ciphersuite, a DST and a random message
    ciphersuite = bbs.ciphersuite('sha256')
    DST_hash_to_field = 'QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_'
    msg = O.random(32)
    **return the table H. H[1] and H[2] will be the two field elements
    H = bbs.hash_to_field_m1_c2(ciphersuite, msg, DST_hash_to_field)
hash_to_curve (ciphersuite, msg, dst)
Hash a message to a point on an elliptic curve. This is a common operation in cryptographic protocols, where messages need to be mapped to curve points for operations like signing and verification. It uses hash_to_field_m1_c2 function to hash the message into two field elements that are mapped to a point on the elliptic curve.

Parameters:

  • ciphersuite
  • msg the input message to be hashed
  • dst a domain separation tag

Returns:

    the final curve point after clearing the cofactor

Usage:

    bbs = require'crypto_bbs'
    **define a ciphersuite, a DST and a random message
    ciphersuite = bbs.ciphersuite('sha256')
    DST_hash_to_field = 'QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_'
    msg = O.random(32)
    **return the curve point
    P = bbs.hash_to_curve(ciphersuite, msg, DST_hash_to_field)
create_generators (ciphersuite, count)
Create a set of cryptographic generators.
These generators are points on an elliptic curve and are used in operations like signing and verification. The function ensures that the generators are created deterministically and securely, based on a seed value and domain separation tags.

Parameters:

  • ciphersuite
  • count the number of generators to create

Returns:

    the first 'count' generators from the ciphersuite.GENERATORS table

Usage:

    bbs = require'crypto_bbs'
    **define a ciphersuite and a count
    ciphersuite = bbs.ciphersuite('sha256')
    count = 5
    **return a table G of 5 generators
    G = bbs.create_generators(ciphersuite,count)
messages_to_scalars (ciphersuite, messages)
Convert a list of messages, a vector of octets, into a list of scalar values using a cryptographic hash function.

Parameters:

  • ciphersuite
  • messages a set of messages

Returns:

    a vector of scalars stored as octet

Usage:

    bbs = require'crypto_bbs'
    **define a ciphersuite and a set of random messages
    ciphersuite = bbs.ciphersuite('sha256')
    map_messages_to_scalar_messages = {
        O.random(32),
        O.random(64),
        O.random(16)
    }
    **return a vector of octets
    output_scalar = bbs.messages_to_scalars(ciphersuite,map_messages_to_scalar_messages)
sign (ciphersuite, sk, header, messages)
The Sign operation returns a BBS signature from a secret key (sk), over a header and a set of messages.
It uses the core_sign function, that computes a deterministic signature from a secret key (sk), a set of generators (points of G1) and optionally a header and a vector of messages.

Parameters:

  • ciphersuite
  • sk the secret key as an octet
  • header
  • messages array of octet strings stored as octet

Returns:

    the signature

Usage:

    bbs = require'crypto_bbs'
    **define a ciphersuite, a secret key, a public key, an header and a message
    ciphersuite = bbs.ciphersuite('sha256')
    SECRET_KEY = "60e55110f76883a13d030b2f6bd11883422d5abde717569fc0731f51237169fc"
    HEADER = "11223344556677889900aabbccddeeff"
    SINGLE_MSG_ARRAY = { O.from_hex("9872ad089e452c7b6e283dfac2a80d58e8d0ff71cc4d5e310a1debdda4a45f02") }
    **calculate the signature for the given message
    output_signature = bbs.sign(ciphersuite, BIG.new(O.from_hex(SECRET_KEY)), O.from_hex(HEADER), SINGLE_MSG_ARRAY)
octets_to_pub_key (pk)
Ensure that the public key is valid, in the right subgroup, and not the identity element. It converts the public key (pk) into a point W on the elliptic curve in G2 and checks if W is in the correct subgroup.

Parameters:

  • pk the public key

Returns:

    the point W

Usage:

    bbs = require'crypto_bbs'
    **define a ciphersuite and a public key
    ciphersuite = bbs.ciphersuite('sha256')
    PUBLIC_KEY = "a820f230f6ae38503b86c70dc50b61c58a77e45c39ab25c0652bbaa8fa136f2851bd4781c9dcde39fc9d1d52c9e60268061e7d7632171d
                  91aa8d460acee0e96f1e7c4cfb12d3ff9ab5d5dc91c277db75c845d649ef3c4f63aebc364cd55ded0c"
    **calculate the point W
    W = bbs.octets_to_pub_key(O.from_hex(PUBLIC_KEY))
verify (ciphersuite, pk, signature, header, messages)
Validate a BBS signature. To do this it uses the core_verify function, which verify if the signature is valid.

Parameters:

  • ciphersuite
  • pk the public key as an octet
  • signature as an octet
  • header
  • messages an array of octet strings as octet

Returns:

    a boolean, true if the signature is valid, false otherwise

Usage:

    **from the usage in the sign function, check if the signature is valid
    if bbs.verify(ciphersuite, O.from_hex(PUBLIC_KEY), output_signature, O.from_hex(HEADER), SINGLE_MSG_ARRAY) then print ("valid signature")
    else print("invalid signature")
    end
    **print:valid signature
calculate_random_scalars (count)
Generate a table of random scalars that are uniformly distributed modulo the ECP order.

Parameters:

  • count number of random scalars to generate

Returns:

    a table of uniformly distributed random scalars modulo the ECP order

Usage:

    **generate a table of 5 random scalars
    T = bbs.calculate_random_scalars(5)
proof_gen (ciphersuite, pk, signature, header, ph, messages, indexes)
Allow a user to prove knowledge of a valid signature while selectively revealing some messages and keeping others hidden. It uses other functions during the process. In particular, the proof_init() function constructs commitments using the signature, public key, message generators, and random scalars. The proof_challenge_calculate function generates a challenge value from the commitments. The proof_finalize function computes the final proof values based on the challenge and initial commitments.

Parameters:

  • ciphersuite
  • pk the public key
  • signature
  • header
  • ph the presentation header
  • messages an array of messages
  • indexes an array of indexes of messages the prover wants to reveal

Returns:

    a zero-knowledge proof that can be verified without revealing the entire signature.

Usage:

    bbs = require'crypto_bbs'
    **define ciphersuite, sk, pk, header, single message array, presentation header and calculate a valid signature
    ciphersuite = bbs.ciphersuite('sha256')
    SECRET_KEY = "60e55110f76883a13d030b2f6bd11883422d5abde717569fc0731f51237169fc"
    PUBLIC_KEY = "a820f230f6ae38503b86c70dc50b61c58a77e45c39ab25c0652bbaa8fa136f2851bd4781c9dcde39fc9d1d52c9e60268061e7d7
                  632171d91aa8d460acee0e96f1e7c4cfb12d3ff9ab5d5dc91c277db75c845d649ef3c4f63aebc364cd55ded0c"
    HEADER = "11223344556677889900aabbccddeeff"
    SINGLE_MSG_ARRAY = { O.from_hex("9872ad089e452c7b6e283dfac2a80d58e8d0ff71cc4d5e310a1debdda4a45f02") }
    PRESENTATION_HEADER = O.from_hex("bed231d880675ed101ead304512e043ade9958dd0241ea70b4b3957fba941501")
    output_signature = bbs.sign(ciphersuite, BIG.new(O.from_hex(SECRET_KEY)), O.from_hex(PUBLIC_KEY), O.from_hex(HEADER), SINGLE_MSG_ARRAY)
    **return the proof like an octet
    pg_output = bbs.proof_gen(ciphersuite, O.from_hex(PUBLIC_KEY), output_signature, O.from_hex(HEADER), PRESENTATION_HEADER, SINGLE_MSG_ARRAY, {1})
proof_verify (ciphersuite, pk, header, ph, messages, indexes)
It is responsible for validating a BBS proof. This proof was generated by proof_gen and allows a verifier to confirm that a signer possesses a valid BBS signature while selectively revealing only some signed messages. It uses some other functions: the octets_to_proof function converts the proof octet string into its mathematical components (group elements and scalars). The proof_verify_init function computes the expected commitments for disclosed and undisclosed messages. The proof_challenge_calculate ensures that the challenge scalar was computed correctly.

Parameters:

  • ciphersuite
  • pk the public key
  • header
  • ph the presentation header
  • messages an array of messages
  • indexes an rray of indexes specifying which messages were disclosed

Returns:

    true if the proof is valid, false otherwise

Usage:

    **from the usage in the proof_gen function, check if the proof is valid
    if  bbs.proof_verify(ciphersuite, O.from_hex(PUBLIC_KEY), pg_output, O.from_hex(HEADER), PRESENTATION_HEADER, SINGLE_MSG_ARRAY, {1}) then print("valid proof")
    else print("invalid proof")
    end
    **print: valid proof
generated by LDoc 1.5.0 Last updated 2025-03-25 10:43:18