decentralized-identity / bbs-signature

The BBS Signature Scheme
https://identity.foundation/bbs-signature/draft-irtf-cfrg-bbs-signatures.html
Apache License 2.0
80 stars 26 forks source link

Messages to Scalars #278

Closed BasileiosKal closed 1 year ago

BasileiosKal commented 1 year ago

Messages need to be mapped to scalar values before they are signed. The criteria on the procedure to do so are flexibility and security.

To allow for predicate proofs, blind/ bound signatures etc, we need to allow for messages to be already scalars before passed to the core operations. An approach is the following

                           + --- msg, if msg a scalar 
                          /
message_to_scalar(msg) = <
                          \
                           + --- hash_to_scalar(msg), if msg an octet string

This is not ideal. Assuming that the prover is relaying to the verifier the msg type, for a given octet-string msg m, they could reveal octets: m or scalar: hash_to_scalar(m) and both would validate.

Option A

Integrity protect a map between msg index and msg type (octets/scalar). This is inspired by U-Prove that does something very similar, as noted by @christianpaquin here.

Specifically, let the bit array enc = enc_1 || enc_2 || ... || enc_L where enc_j := msg_j is a scalar. Then enc will be computed in Sign, Verify and ProofGen and added to the domain.

In ProofVerify, the enc value cannot be computed (not all messages will be known). There are 2 options,

In any case, in ProofVerify, the disclosed messages type should be checked against enc.

Advantages

This avoids the above issue of the prover revealing msgs as scalars that they where signed as octets.

Disadvantages

A breaking change. It will add a fare amount of steps for something that is an extension point. It will require changes to the proof value or the ProofVerify api.

Option B

Similar to option A but layered on top of the current core operations. Allow for higher level applications to define schemas that will be passed to the header (instead of the domain as in option A).

We can pass the header (that will encode the schema) to the messages_to_scalars and map_to_scalar operations.

Assume the schema is encoded as the enc bit array defined above, we can set header = enc || old_header. Then we will map a msg like

scalar_value = map_to_scalar(msg, idx, header)

Procedure:

1. if header[idx] == 1 and msg a scalar: return msg
2. else if header[idx] == 0 and msg an octet string: return hash_to_scalar(msg)
3. else return INVALID

Advantages

Solves the issue. Not a breaking change. Minimum updates in general.

Disadvantages

We can't define the above map_to_scalar in the core draft, if we don't want to define the concept of a schema (i.e., of the enc bit array that will be added to the header).

BasileiosKal commented 1 year ago

Couple of alternatives:

None of this will require a breaking change (or even a change to a procedure step).

BasileiosKal commented 1 year ago

Closing after #287 was merged