Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PK format and validation #266

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 42 additions & 47 deletions draft-irtf-cfrg-bbs-signatures.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,8 @@ point\_to\_octets\_g1(P) -> ostr, point\_to\_octets\_g2(P) -> ostr
octets\_to\_point\_g1(ostr) -> P, octets\_to\_point\_g2(ostr) -> P
: 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.

subgroup\_check(P) -> VALID or INVALID
: 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., [@Bowe19].
subgroup\_check\_g2(P) -> VALID or INVALID
: returns VALID if the point P is in a subgroup of order `r` of E2, and INVALID otherwise. This function can always be implemented by checking that r \* P is equal to the identity element of E2. In some cases, faster checks may also exist, e.g., [@Bowe19].

## Document Organization

Expand Down Expand Up @@ -350,8 +350,7 @@ Outputs:

Procedure:

1. W = SK * P2
2. return point_to_octets_g2(W)
1. return SK * P2
```

## Core Operations
Expand All @@ -364,6 +363,8 @@ The operations of this section make use of functions and sub-routines defined in

The following operations also make use of the `create_generators` operation defined in (#generators-calculation), to create generator points on `G1` (see [Messages and Generators](#generators)). Note that the values of those points depends only on a cipheruite defined seed. As a result, the output of that operation can be cached to avoid unnecessary calls to the `create_generators` procedure. See (#generators-calculation) for more details.

All core operations defined in this section, accept as input the Issuer's public key (PK), as point of G2 different from the `Identity_G2`. Checking the public key validity, before passing it to one of the core operations is crucial. The PK MUST be checked using the `public_key_validate` operation defined in (#public-key-validation). Not checking the PK, creates severe security vulnerabilities. See (#validating-public-keys) for more details.

### Signature Generation (Sign)

This operation computes a deterministic signature from a secret key (SK) and optionally over a header and or a vector of messages (as scalar values, see [Messages](#messages)).
Expand All @@ -375,8 +376,9 @@ 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.
- PK (REQUIRED), a point of G2, different from the Identity_G2 point,
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.
Expand Down Expand Up @@ -431,8 +433,7 @@ result = Verify(PK, signature, header, messages)

Inputs:

- PK (REQUIRED), an octet string of the form outputted by the SkToPk
operation.
- PK (REQUIRED), a point of G2, different from the Identity_G2 point.
- signature (REQUIRED), an octet string of the form outputted by the
Sign operation.
- header (OPTIONAL), an octet string containing context and application
Expand All @@ -459,18 +460,16 @@ Deserialization:
1. signature_result = octets_to_signature(signature)
2. if signature_result is INVALID, return INVALID
3. (A, e) = signature_result
4. W = octets_to_pubkey(PK)
5. if W is INVALID, return INVALID
6. L = length(messages)
7. (msg_1, ..., msg_L) = messages
4. L = length(messages)
5. (msg_1, ..., msg_L) = messages

Procedure:

1. (Q_1, H_1, ..., H_L) = create_generators(L+1)
2. domain = calculate_domain(PK, Q_1, (H_1, ..., H_L), header)
3. if domain is INVALID, return INVALID
4. B = P1 + Q_1 * domain + H_1 * msg_1 + ... + H_L * msg_L
5. if e(A, W + P2 * e) * e(B, -P2) != Identity_GT, return INVALID
5. if e(A, PK + P2 * e) * e(B, -P2) != Identity_GT, return INVALID
6. return VALID
```

Expand All @@ -489,8 +488,7 @@ proof = ProofGen(PK, signature, header, ph, messages, disclosed_indexes)

Inputs:

- PK (REQUIRED), an octet string of the form outputted by the SkToPk
operation.
- PK (REQUIRED), a point of G2, different from the Identity_G2 point.
- signature (REQUIRED), an octet string of the form outputted by the
Sign operation.
- header (OPTIONAL), an octet string containing context and application
Expand Down Expand Up @@ -572,8 +570,7 @@ result = ProofVerify(PK, proof, header, ph,

Inputs:

- PK (REQUIRED), an octet string of the form outputted by the SkToPk
operation.
- PK (REQUIRED), a point of G2, different from the Identity_G2 point.
- proof (REQUIRED), an octet string of the form outputted by the
ProofGen operation.
- header (OPTIONAL), an optional octet string containing context and
Expand Down Expand Up @@ -610,15 +607,13 @@ Deserialization:
1. proof_result = octets_to_proof(proof)
2. if proof_result is INVALID, return INVALID
3. (Abar, Bbar, c, r2^, r3^, commitments) = proof_result
4. W = octets_to_pubkey(PK)
5. if W is INVALID, return INVALID
6. U = length(commitments)
7. R = length(disclosed_indexes)
8. L = R + U
9. (i1, ..., iR) = disclosed_indexes
10. (j1, ..., jU) = range(1, L) \ disclosed_indexes
11. (msg_i1, ..., msg_iR) = disclosed_messages
12. (m^_j1, ...., m^_jU) = commitments
4. U = length(commitments)
5. R = length(disclosed_indexes)
6. L = R + U
7. (i1, ..., iR) = disclosed_indexes
8. (j1, ..., jU) = range(1, L) \ disclosed_indexes
9. (msg_i1, ..., msg_iR) = disclosed_messages
10. (m^_j1, ...., m^_jU) = commitments

Preconditions:

Expand All @@ -637,10 +632,10 @@ Procedure:
7. D = P1 + Q_1 * domain + H_i1 * msg_i1 + ... + H_iR * msg_iR
8. C = Bbar * r2^ + Abar * r3^ + H_j1 * m^_j1 + ... + H_jU * m^_jU + D * c
9. cv = calculate_challenge(Abar, Bbar, C, (i1, ..., iR),
(msg_i1, ..., msg_iR), domain, ph)
(msg_i1, ..., msg_iR), domain, ph)
10. if cv is INVALID, return INVALID
11. if c != cv, return INVALID
12. if e(Abar, W) * e(Bbar, -P2) != Identity_GT, return INVALID
12. if e(Abar, PK) * e(Bbar, -P2) != Identity_GT, return INVALID
13. return VALID
```

Expand Down Expand Up @@ -830,21 +825,21 @@ Procedure:

## Domain Calculation

This operation calculates the domain value, a scalar representing the distillation of all essential contextual information for a signature. The same domain value must be calculated by all parties (the signer, the prover, and the verifier) for both the signature and proofs to be validated.
This operation calculates the domain value, a scalar representing the distillation of all essential contextual information for a signature. The same domain value must be calculated by all parties (the Signer, the Prover, and the Verifier) for both the signature and proofs to be validated.

The input to the domain value includes an octet string called the header, chosen by the signer and meant to encode any information that is required to be revealed by the prover (such as an expiration date, or an identifier for the target audience). This is in contrast to the signed message values, which may be withheld during a proof.

When a signature is calculated, the domain value is combined with a specific generator point (`Q_1`, see [Sign](#signature-generation-sign)) to protect the integrity of the public parameters and the header.

This operation makes use of the `serialize` function, defined in [Section 4.6.1](#serialize).
This operation makes use of the `serialize` and `hash_to_scalar` functions, defined in (#serialize) and (#hash-to-scalar) respectively.

```
domain = calculate_domain(PK, Q_1, H_Points, header)

Inputs:

- PK (REQUIRED), an octet string, representing the public key of the
Signer of the form outputted by the SkToPk operation.
- PK (REQUIRED), a point of G2, different from the Identity_G2 point,
representing the Signer's public key.
- Q_1 (REQUIRED), point of G1 (the first point returned from
create_generators).
- H_Points (REQUIRED), array of points of G1.
Expand All @@ -864,10 +859,10 @@ Procedure:
1. L = length(H_Points)
2. if length(header) > 2^64 - 1 or L > 2^64 - 1, return INVALID
3. (H_1, ..., H_L) = H_Points
4. dom_array = (L, Q_1, H_1, ..., H_L)
4. dom_array = (PK, L, Q_1, H_1, ..., H_L)
5. dom_octs = serialize(dom_array) || ciphersuite_id
6. if dom_octs is INVALID, return INVALID
7. dom_input = PK || dom_octs || I2OSP(length(header), 8) || header
7. dom_input = dom_octs || I2OSP(length(header), 8) || header
8. domain = hash_to_scalar(dom_input)
9. if domain is INVALID, return INVALID
10. return domain
Expand Down Expand Up @@ -1111,40 +1106,40 @@ Procedure:

16. if index != length(proof_octets), return INVALID
17. msg_commitments = ()
18. If j > 3, set msg_commitments = (s_3, ..., s_(j-1))
18. if j > 3, set msg_commitments = (s_3, ..., s_(j-1))
19. return (A_0, A_1, s_0, s_1, s_2, msg_commitments)
```

### Octets to Public Key
## Public Key Validation

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.
This operation describes how to validate the Signer's public key (PK). It uses the `subgroup_check_g2` operation defined in [Notation](#notation). It requires the PK to be a valid point of G2 different from the identity point.

```
W = octets_to_pubkey(PK)
result = public_key_validate(PK)

Inputs:

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

Outputs:

- W, a valid point in G2 or INVALID
- result, either VALID 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
1. if PK not a point of E2, return INVALID
2. if subgroup_check_g2(PK) is INVALID, return INVALID
3. if PK == Identity_G2, return INVALID
4. return VALID
```

**Note** Checking that a point is on the E2 curve (step 1 of the above operation) can be implemented by validating that the `(x, y)` coordinates of the inputted point `PK = (x, y)`, satisfies the equation of the elliptic curve E2.

# Security Considerations

## Validating Public Keys

It is RECOMENDED for any operation in [Core Operations](#core-operations) involving public keys, that they deserialize the public key first using the [OctetsToPublicKey](#octetstopublickey) operation, even if they only require the octet-string representation of the public key. If the `octets_to_pubkey` procedure (see the [OctetsToPublicKey](#octetstopublickey) section) returns INVALID, the calling operation should also return INVALID and abort. An example of where this recommendation applies is the [Sign](#sign) operation. An example of where an explicit invocation to the `octets_to_pubkey` operation is already defined and therefore required is the [Verify](#signature-verification-verify) operation.
All core algorithms defined in (#core-operations) require the Signer's public key (PK) as input. Note that the core algorithms expect PK to be a valid point of G2 different from the Identity point. It is REQUIRED to use `public_key_validate` defined in (#public-key-validation) to validate the PK. If `public_key_validate` returns INVALID the application MUST abort. As an optimization, implementations MAY cache the result of the `public_key_validate` operation, to avoid unnecessarily repeating validation for known valid public keys.

## Point Deserialization

Expand Down