From efe79c3e117ee7d907da2d0f877774a11df21d75 Mon Sep 17 00:00:00 2001 From: Vasilis Kalos Date: Mon, 5 Jun 2023 19:54:25 +0300 Subject: [PATCH 01/13] update ciphersuite format --- draft-irtf-cfrg-bbs-signatures.md | 190 ++++++++++++++++-------------- 1 file changed, 104 insertions(+), 86 deletions(-) diff --git a/draft-irtf-cfrg-bbs-signatures.md b/draft-irtf-cfrg-bbs-signatures.md index 507ca5f5..daa607b6 100644 --- a/draft-irtf-cfrg-bbs-signatures.md +++ b/draft-irtf-cfrg-bbs-signatures.md @@ -408,16 +408,18 @@ Deserialization: 1. L = length(messages) 2. (msg_1, ..., msg_L) = messages +Preconditions: + +1. if L > 2^64 - 1 or length(header) > 2^64 - 1, return INVALID + 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. e = hash_to_scalar(serialize((SK, domain, msg_1, ..., msg_L))) -5. if e is INVALID, return INVALID -6. B = P1 + Q_1 * domain + H_1 * msg_1 + ... + H_L * msg_L -7. A = B * (1 / (SK + e)) -8. return signature_to_octets(A, e) +3. e = hash_to_scalar(serialize((SK, domain, msg_1, ..., msg_L))) +4. B = P1 + Q_1 * domain + H_1 * msg_1 + ... + H_L * msg_L +5. A = B * (1 / (SK + e)) +6. return signature_to_octets(A, e) ``` **Note** When computing step 12 of the above procedure there is an extremely small probability (around `2^(-r)`) that the condition `(SK + e) = 0 mod r` will be met. How implementations evaluate the inverse of the scalar value `0` may vary, with some returning an error and others returning `0` as a result. If the returned value from the inverse operation `1/(SK + e)` does evaluate to `0` the value of `A` will equal `Identity_G1` thus an invalid signature. Implementations MAY elect to check `(SK + e) = 0 mod r` prior to step 9, and or `A != Identity_G1` after step 9 to prevent the production of invalid signatures. @@ -464,14 +466,17 @@ Deserialization: 6. L = length(messages) 7. (msg_1, ..., msg_L) = messages +Preconditions: + +1. if L > 2^64 - 1 or length(header) > 2^64 - 1, return INVALID + 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 -6. return VALID +3. B = P1 + Q_1 * domain + H_1 * msg_1 + ... + H_L * msg_L +4. if e(A, W + P2 * e) * e(B, -P2) != Identity_GT, return INVALID +5. return VALID ``` ### Proof Generation (ProofGen) @@ -496,8 +501,8 @@ Inputs: - header (OPTIONAL), an octet string containing context and application specific information. If not supplied, it defaults to an empty string. -- ph (OPTIONAL), an octet string containing the presentation header. If not - supplied, it defaults to an empty string. +- ph (OPTIONAL), an 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 @@ -528,12 +533,19 @@ Deserialization: 3. (A, e) = signature_result 4. L = length(messages) 5. R = length(disclosed_indexes) -6. U = L - R -7. (i1, ..., iR) = disclosed_indexes -8. (j1, ..., jU) = range(1, L) \ disclosed_indexes -9. (msg_1, ..., msg_L) = messages -10. (msg_i1, ..., msg_iR) = (messages[i1], ..., messages[iR]) -11. (msg_j1, ..., msg_jU) = (messages[j1], ..., messages[jU]) +6. if R > L, return INVALID +7. U = L - R +8. (i1, ..., iR) = disclosed_indexes +9. (j1, ..., jU) = range(1, L) \ disclosed_indexes +10. (msg_1, ..., msg_L) = messages +11. (msg_i1, ..., msg_iR) = (messages[i1], ..., messages[iR]) +12. (msg_j1, ..., msg_jU) = (messages[j1], ..., messages[jU]) + +Preconditions: + +1. if L > 2^64 - 1 or length(header) > 2^64 - 1, return INVALID +2. if length(ph) > 2^64 - 1, return INVALID +3. if R > 2^64 - 1, return INVALID Procedure: @@ -541,22 +553,20 @@ Procedure: 2. (H_1, ..., H_L) = MsgGenerators 3. (H_j1, ..., H_jU) = (MsgGenerators[j1], ..., MsgGenerators[jU]) 4. domain = calculate_domain(PK, Q_1, (H_1, ..., H_L), header) -5. if domain is INVALID, return INVALID -6. random_scalars = calculate_random_scalars(3+U) -7. (r1, r2, r3, m~_j1, ..., m~_jU) = random_scalars -8. B = P1 + Q_1 * domain + H_1 * msg_1 + ... + H_L * msg_L -9. Abar = A * r1 -10. Bbar = B * r1 - Abar * e -11. C = Bbar * r2 + Abar * r3 + H_j1 * m~_j1 + ... + H_jU * m~_jU -12. c = calculate_challenge(Abar, Bbar, C, (i1, ..., iR), - (msg_i1, ..., msg_iR), domain, ph) -13. if c is INVALID, return INVALID -14. r4 = - r1^-1 (mod r) -15. r2^ = r2 + r4 * c (mod r) -16. r3^ = r3 + e * r4 * c (mod r) -17. for j in (j1, ..., jU): m^_j = m~_j + msg_j * c (mod r) -18. proof = (Abar, Bbar, c, r2^, r3^, (m^_j1, ..., m^_jU)) -19. return proof_to_octets(proof) +5. random_scalars = calculate_random_scalars(3+U) +6. (r1, r2, r3, m~_j1, ..., m~_jU) = random_scalars +7. B = P1 + Q_1 * domain + H_1 * msg_1 + ... + H_L * msg_L +8. Abar = A * r1 +9. Bbar = B * r1 - Abar * e +10. C = Bbar * r2 + Abar * r3 + H_j1 * m~_j1 + ... + H_jU * m~_jU +11. c = calculate_challenge(Abar, Bbar, C, (i1, ..., iR), + (msg_i1, ..., msg_iR), domain, ph) +12. r4 = - r1^-1 (mod r) +13. r2^ = r2 + r4 * c (mod r) +14. r3^ = r3 + e * r4 * c (mod r) +15. for j in (j1, ..., jU): m^_j = m~_j + msg_j * c (mod r) +16. proof = (Abar, Bbar, c, r2^, r3^, (m^_j1, ..., m^_jU)) +17. return proof_to_octets(proof) ``` ### Proof Verification (ProofVerify) @@ -622,8 +632,11 @@ Deserialization: Preconditions: -1. for i in (i1, ..., iR), if i < 1 or i > L, return INVALID -2. if length(disclosed_messages) != R, return INVALID +1. if L > 2^64 - 1 or length(header) > 2^64 - 1, return INVALID +2. if length(ph) > 2^64 - 1, return INVALID +3. if R > 2^64 - 1, return INVALID +4. for i in (i1, ..., iR), if i < 1 or i > L, return INVALID +5. if length(disclosed_messages) != R, return INVALID Procedure: @@ -631,17 +644,14 @@ Procedure: 2. (H_1, ..., H_L) = MsgGenerators 3. (H_i1, ..., H_iR) = (MsgGenerators[i1], ..., MsgGenerators[iR]) 4. (H_j1, ..., H_jU) = (MsgGenerators[j1], ..., MsgGenerators[jU]) - 5. domain = calculate_domain(PK, Q_1, (H_1, ..., H_L), header) -6. if domain is INVALID, return INVALID -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) -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 -13. return VALID +6. D = P1 + Q_1 * domain + H_i1 * msg_i1 + ... + H_iR * msg_iR +7. C = Bbar * r2^ + Abar * r3^ + H_j1 * m^_j1 + ... + H_jU * m^_jU + D * c +8. cv = calculate_challenge(Abar, Bbar, C, (i1, ..., iR), + (msg_i1, ..., msg_iR), domain, ph) +9. if c != cv, return INVALID +10. if e(Abar, W) * e(Bbar, -P2) != Identity_GT, return INVALID +11. return VALID ``` # Utility Operations @@ -772,9 +782,7 @@ Outputs: Procedure: 1. if length(msg) > 2^64 - 1 or length(dst) > 255 return INVALID -2. msg_scalar = hash_to_scalar(msg, dst) -3. if msg_scalar is INVALID, return INVALID -4. return msg_scalar +2. return hash_to_scalar(msg, dst) ``` ## Hash to Scalar @@ -783,7 +791,7 @@ This operation describes how to hash an arbitrary octet string to `n` scalar val This operation makes use of expand\_message defined in [@!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). 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). Note however, that the hash\_to\_curve document, makes use of hash\_to\_field with the target group being the multiplicative group of integers mod p (Fp). For this reason, we don’t directly use hash\_to\_field here, rather we define a similar operation (hash\_to\_scalar), making direct use of the expand\_message function, that will be defined by the hash-to-curve suite used (i.e., either expand\_message\_xmd or expand\_message\_xof). 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). -The operation takes as input an octet string representing the message to hash (msg), the number of the scalars to return (count) as well as an optional domain separation tag (dst). If a dst is not supplied, its value MUST default to the octet string returned from ciphersuit\_id || "H2S\_", where ciphersuite\_id is the octet string representing the unique ID of the ciphersuite and "H2S_" is an ASCII string comprised of 4 bytes. +The operation takes as input an octet string representing the message to hash (msg), the number of the scalars to return (count) as well as an optional domain separation tag (dst). The length of the dst MUST be less than 255 octets. See section 5.3.3 of [@!I-D.irtf-cfrg-hash-to-curve] for guidance on using larger dst values. If a dst is not supplied, its value MUST default to the octet string returned from ciphersuit\_id || "H2S\_", where ciphersuite\_id is the octet string representing the unique ID of the ciphersuite and "H2S_" is an ASCII string comprised of 4 bytes. **Note** It is possible that the `hash_to_scalar` procedure will return an error, if the underlying `expand_message` operation aborts. See [@!I-D.irtf-cfrg-hash-to-curve], Section 5.3, for more details on the cases that `expand_message` will abort (note that the input term `len_in_bytes` of `expand_message` in the Hash-to-Curve document equals `count * expand_len` in our case). @@ -816,16 +824,15 @@ Outputs: Procedure: -1. counter = 0 -2. hashed_scalar = 0 -3. while hashed_scalar == 0: -4. if counter > 255, return INVALID -5. msg_prime = msg_octets || I2OSP(counter, 1) -6. uniform_bytes = expand_message(msg_prime, dst, expand_len) -7. if uniform_bytes is INVALID, return INVALID -8. hashed_scalar = OS2IP(uniform_bytes) mod r -9. counter = counter + 1 -10. return hashed_scalar +1. counter = 0 +2. hashed_scalar = 0 +3. while hashed_scalar == 0: +4. if counter > 255, return INVALID +5. msg_prime = msg_octets || I2OSP(counter, 1) +6. uniform_bytes = expand_message(msg_prime, dst, expand_len) +7. hashed_scalar = OS2IP(uniform_bytes) mod r +8. counter = counter + 1 +9. return hashed_scalar ``` ## Domain Calculation @@ -859,18 +866,22 @@ Outputs: - domain, a scalar value or INVALID. +Deserialization: + +1. L = length(H_Points) +2. (H_1, ..., H_L) = H_Points + +Preconditions: + +1. if length(header) > 2^64 - 1 or L > 2^64 - 1, return INVALID + 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) -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 -8. domain = hash_to_scalar(dom_input) -9. if domain is INVALID, return INVALID -10. return domain +1. dom_array = (L, Q_1, H_1, ..., H_L) +2. dom_octs = serialize(dom_array) || ciphersuite_id +3. if dom_octs is INVALID, return INVALID +4. dom_input = PK || dom_octs || I2OSP(length(header), 8) || header +5. return hash_to_scalar(dom_input) ``` **Note**: If the header is not supplied in `calculate_domain`, it defaults to the empty octet string (""). This means that in the concatenation step of the above procedure (step 7), 8 bytes representing a length of 0 (i.e., `0x0000000000000000`), will still need to be appended at the end, even though a header value is not provided. @@ -887,8 +898,7 @@ challenge = calculate_challenge(Abar, Bbar, C, i_array, Inputs: -- (Abar, Bbar, C) (REQUIRED), points of G1, as calculated in - ProofGen. +- (Abar, Bbar, C) (REQUIRED), points of G1, as calculated in ProofGen. - i_array (REQUIRED), array of non-negative integers (the indexes of the disclosed messages). - msg_array (REQUIRED), array of scalars (the disclosed messages). @@ -900,21 +910,23 @@ Outputs: - challenge, a scalar or INVALID. +Deserialization: + +1. R = length(i_array) +2. (i1, ..., iR) = i_array +3. (msg_i1, ..., msg_iR) = msg_array + +Preconditions: + +1. if R > 2^64 - 1 or R != length(msg_array), return INVALID +2. if length(ph) > 2^64 - 1, return INVALID + Procedure: -1. R = length(i_array) -2. if R > 2^64 - 1 or R != length(msg_array), return INVALID -3. if length(ph) > 2^64 - 1, return INVALID -4. (i1, ..., iR) = i_array -5. (msg_i1, ..., msg_iR) = msg_array -6. c_array = (Abar, Bbar, C, R, i1, ..., iR, - msg_i1, ..., msg_iR, domain) -7. c_octs = serialize(c_array) -8. if c_octs is INVALID, return INVALID -9. c_input = c_octs || I2OSP(length(ph), 8) || ph -10. challenge = hash_to_scalar(c_input) -11. if challenge is INVALID, return INVALID -12. return challenge +1. c_arr = (Abar, Bbar, C, R, i1, ..., iR, msg_i1, ..., msg_iR, domain) +2. c_octs = serialize(c_array) +3. if c_octs is INVALID, return INVALID +4. return hash_to_scalar(c_octs || I2OSP(length(ph), 8) || ph) ``` **Note**: Similarly to the header value in [Domain Calculation](#domain-calculation), if the presentation header (ph) is not supplied in `calculate_challenge`, 8 bytes representing a length of 0 (i.e., `0x0000000000000000`), must still be appended after the `c_octs` value, during the concatenation step of the above procedure (step 9). @@ -1228,6 +1240,8 @@ The parameters that each ciphersuite needs to define are generally divided into - hash\_to\_curve\_suite: The hash-to-curve ciphersuite id, in the form defined in [@!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 [Notation](#notation) section) and the expand\_message (either expand\_message\_xmd or expand\_message\_xof) operations used in this document. +- expand\_len: the length to expand a message to, during hash\_to\_scalar in (#hash-to-scalar). This length MUST be defined in a way that will not cause the expand\_message operation specified by the hash\_to\_curve\_suite to abort. It MUST also be defined to be larger than `ceil((ceil(log2(r))+k)/8)`, where `log2(r)` and `k` are defined by each ciphersuite. If both of those restrictions cannot be satisfied, a different hash\_to\_curve suite and curve may be chosen. + - P1: A fixed point in the G1 subgroup. **Serialization functions**: @@ -1250,7 +1264,7 @@ a function that returns the point P in the subgroup G2 corresponding to the cano ## BLS12-381 Ciphersuites -The following two ciphersuites are based on the BLS12-381 elliptic curves defined in Section 4.2.1 of [@!I-D.irtf-cfrg-pairing-friendly-curves]. The targeted security level of both suites in bits is `k = 128`. +The following two ciphersuites are based on the BLS12-381 elliptic curves defined in Section 4.2.1 of [@!I-D.irtf-cfrg-pairing-friendly-curves]. For both suites, the targeted security level in bits is `k = 128` and the length of the group order is `log2(r) = 255`. The first ciphersuite makes use of an extendable output function, and most specifically of SHAKE-256, as defined in Section 6.2 of [@!SHA3]. It also uses the hash-to-curve suite defined by this document in [Appendix A.1](#bls12-381-hash_to_curve-def), which also makes use of the SHAKE-256 function. @@ -1272,6 +1286,8 @@ Note that these two ciphersuites differ only in the hash function (SHAKE-256 vs - hash\_to\_curve\_suite: "BLS12381G1\_XOF:SHAKE-256\_SSWU\_RO\_" as defined in [Appendix A.1](#bls12-381-hash-to-curve-definition-using-shake-256) for the G1 subgroup. +- expand\_len: 48 ( `= ceil((ceil(log2(r))+k)/8)`) + - P1: The G1 point returned from the `create_generators` procedure, with generator\_seed = "BBS\_BLS12381G1\_XOF:SHAKE-256\_SSWU\_RO\_BP\_MESSAGE\_GENERATOR\_SEED". More specifically, ``` P1 = {{ $generatorFixtures.bls12-381-shake-256.generators.BP }} @@ -1306,6 +1322,8 @@ Note that these two ciphersuites differ only in the hash function (SHAKE-256 vs - hash\_to\_curve\_suite: "BLS12381G1\_XMD:SHA-256\_SSWU\_RO\_" as defined in Section 8.8.1 of the [@!I-D.irtf-cfrg-hash-to-curve] for the G1 subgroup. +- expand\_len: 48 ( `= ceil((ceil(log2(r))+k)/8)`) + - P1: The G1 point returned from the `create_generators` procedure, with generator\_seed = "BBS\_BLS12381G1\_XMD:SHA-256\_SSWU\_RO\_BP\_MESSAGE\_GENERATOR\_SEED". More specifically, ``` P1 = {{ $generatorFixtures.bls12-381-sha-256.generators.BP }} From 707e12e66a323b7f9184aa603a707709a6785793 Mon Sep 17 00:00:00 2001 From: Vasilis Kalos Date: Mon, 12 Jun 2023 17:08:19 +0300 Subject: [PATCH 02/13] rm whitespace --- draft-irtf-cfrg-bbs-signatures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/draft-irtf-cfrg-bbs-signatures.md b/draft-irtf-cfrg-bbs-signatures.md index daa607b6..550cbd4f 100644 --- a/draft-irtf-cfrg-bbs-signatures.md +++ b/draft-irtf-cfrg-bbs-signatures.md @@ -646,7 +646,7 @@ Procedure: 4. (H_j1, ..., H_jU) = (MsgGenerators[j1], ..., MsgGenerators[jU]) 5. domain = calculate_domain(PK, Q_1, (H_1, ..., H_L), header) 6. D = P1 + Q_1 * domain + H_i1 * msg_i1 + ... + H_iR * msg_iR -7. C = Bbar * r2^ + Abar * r3^ + H_j1 * m^_j1 + ... + H_jU * m^_jU + D * c +7. C = Bbar * r2^ + Abar * r3^ + H_j1 * m^_j1 + ... + H_jU * m^_jU + D * c 8. cv = calculate_challenge(Abar, Bbar, C, (i1, ..., iR), (msg_i1, ..., msg_iR), domain, ph) 9. if c != cv, return INVALID From c3b62531e86181948f1db82f8a2c75eb2a1e0144 Mon Sep 17 00:00:00 2001 From: Vasilis Kalos Date: Mon, 12 Jun 2023 18:16:48 +0300 Subject: [PATCH 03/13] implicit error handling --- draft-irtf-cfrg-bbs-signatures.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/draft-irtf-cfrg-bbs-signatures.md b/draft-irtf-cfrg-bbs-signatures.md index 550cbd4f..23e7ffb8 100644 --- a/draft-irtf-cfrg-bbs-signatures.md +++ b/draft-irtf-cfrg-bbs-signatures.md @@ -364,6 +364,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. +**Note** The utility functions used by the core operations of this section could fail (return INVALID). In that case, the calling operation MUST also immediately return INVALID and abort. Because under normal execution (i.e., given the correctness of the input arguments and execution of the procedure's steps), the conditions for a sub-routine to return INVALID will not be met, to increase readability the core operations do not perform explicit checks on the sub-routines results. However, an implementation should be able to catch such errors (i.e., a sub-routine returning INVALID) and abort execution. + ### 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)). @@ -791,7 +793,7 @@ This operation describes how to hash an arbitrary octet string to `n` scalar val This operation makes use of expand\_message defined in [@!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). 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). Note however, that the hash\_to\_curve document, makes use of hash\_to\_field with the target group being the multiplicative group of integers mod p (Fp). For this reason, we don’t directly use hash\_to\_field here, rather we define a similar operation (hash\_to\_scalar), making direct use of the expand\_message function, that will be defined by the hash-to-curve suite used (i.e., either expand\_message\_xmd or expand\_message\_xof). 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). -The operation takes as input an octet string representing the message to hash (msg), the number of the scalars to return (count) as well as an optional domain separation tag (dst). The length of the dst MUST be less than 255 octets. See section 5.3.3 of [@!I-D.irtf-cfrg-hash-to-curve] for guidance on using larger dst values. If a dst is not supplied, its value MUST default to the octet string returned from ciphersuit\_id || "H2S\_", where ciphersuite\_id is the octet string representing the unique ID of the ciphersuite and "H2S_" is an ASCII string comprised of 4 bytes. +The operation takes as input an octet string representing the message to hash (msg), the number of the scalars to return (count) as well as an optional domain separation tag (dst). The length of the dst MUST be less than 255 octets. See section 5.3.3 of [@!I-D.irtf-cfrg-hash-to-curve] for guidance on using larger dst values. If a dst is not supplied, its value MUST default to the octet string returned from ciphersuite\_id || "H2S\_", where ciphersuite\_id is the octet string representing the unique ID of the ciphersuite and "H2S_" is an ASCII string comprised of 4 bytes. **Note** It is possible that the `hash_to_scalar` procedure will return an error, if the underlying `expand_message` operation aborts. See [@!I-D.irtf-cfrg-hash-to-curve], Section 5.3, for more details on the cases that `expand_message` will abort (note that the input term `len_in_bytes` of `expand_message` in the Hash-to-Curve document equals `count * expand_len` in our case). @@ -855,8 +857,8 @@ Inputs: - Q_1 (REQUIRED), point of G1 (the first point returned from create_generators). - H_Points (REQUIRED), array of points of G1. -- header (OPTIONAL), an octet string. If not supplied, it must default to - the empty octet string (""). +- header (OPTIONAL), an octet string. If not supplied, it must default + to the empty octet string (""). Parameters: @@ -879,12 +881,11 @@ Procedure: 1. dom_array = (L, Q_1, H_1, ..., H_L) 2. dom_octs = serialize(dom_array) || ciphersuite_id -3. if dom_octs is INVALID, return INVALID -4. dom_input = PK || dom_octs || I2OSP(length(header), 8) || header -5. return hash_to_scalar(dom_input) +3. dom_input = PK || dom_octs || I2OSP(length(header), 8) || header +4. return hash_to_scalar(dom_input) ``` -**Note**: If the header is not supplied in `calculate_domain`, it defaults to the empty octet string (""). This means that in the concatenation step of the above procedure (step 7), 8 bytes representing a length of 0 (i.e., `0x0000000000000000`), will still need to be appended at the end, even though a header value is not provided. +**Note**: If the header is not supplied in `calculate_domain`, it defaults to the empty octet string (""). This means that in the concatenation step of the above procedure (step 3), 8 bytes representing a length of 0 (i.e., `0x0000000000000000`), will still need to be appended at the end, even though a header value is not provided. ## Challenge Calculation @@ -920,15 +921,15 @@ Preconditions: 1. if R > 2^64 - 1 or R != length(msg_array), return INVALID 2. if length(ph) > 2^64 - 1, return INVALID +3. for i in i_array, if i > 2^64 - 1, return INVALID Procedure: 1. c_arr = (Abar, Bbar, C, R, i1, ..., iR, msg_i1, ..., msg_iR, domain) 2. c_octs = serialize(c_array) -3. if c_octs is INVALID, return INVALID -4. return hash_to_scalar(c_octs || I2OSP(length(ph), 8) || ph) +3. return hash_to_scalar(c_octs || I2OSP(length(ph), 8) || ph) ``` -**Note**: Similarly to the header value in [Domain Calculation](#domain-calculation), if the presentation header (ph) is not supplied in `calculate_challenge`, 8 bytes representing a length of 0 (i.e., `0x0000000000000000`), must still be appended after the `c_octs` value, during the concatenation step of the above procedure (step 9). +**Note**: Similarly to the header value in [Domain Calculation](#domain-calculation), if the presentation header (ph) is not supplied in `calculate_challenge`, 8 bytes representing a length of 0 (i.e., `0x0000000000000000`), must still be appended after the `c_octs` value, during the concatenation step of the above procedure (step 3). ## Serialization @@ -1240,7 +1241,7 @@ The parameters that each ciphersuite needs to define are generally divided into - hash\_to\_curve\_suite: The hash-to-curve ciphersuite id, in the form defined in [@!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 [Notation](#notation) section) and the expand\_message (either expand\_message\_xmd or expand\_message\_xof) operations used in this document. -- expand\_len: the length to expand a message to, during hash\_to\_scalar in (#hash-to-scalar). This length MUST be defined in a way that will not cause the expand\_message operation specified by the hash\_to\_curve\_suite to abort. It MUST also be defined to be larger than `ceil((ceil(log2(r))+k)/8)`, where `log2(r)` and `k` are defined by each ciphersuite. If both of those restrictions cannot be satisfied, a different hash\_to\_curve suite and curve may be chosen. +- expand\_len: The length to expand a message to, during hash\_to\_scalar in (#hash-to-scalar). This length MUST be defined in a way that will not cause the expand\_message operation specified by the hash\_to\_curve\_suite to abort. It MUST also be defined to be larger than `ceil((ceil(log2(r))+k)/8)`, where `log2(r)` and `k` are defined by each ciphersuite. If both of those restrictions cannot be satisfied, a different hash\_to\_curve suite and curve may be chosen. - P1: A fixed point in the G1 subgroup. From bdaf8fc70a28df1738577872d506fee9af37ed8b Mon Sep 17 00:00:00 2001 From: Vasilis Kalos Date: Wed, 14 Jun 2023 14:26:16 +0300 Subject: [PATCH 04/13] add ABORT --- draft-irtf-cfrg-bbs-signatures.md | 90 +++++++++++++++---------------- 1 file changed, 42 insertions(+), 48 deletions(-) diff --git a/draft-irtf-cfrg-bbs-signatures.md b/draft-irtf-cfrg-bbs-signatures.md index 23e7ffb8..4fad80e5 100644 --- a/draft-irtf-cfrg-bbs-signatures.md +++ b/draft-irtf-cfrg-bbs-signatures.md @@ -166,6 +166,9 @@ I2OSP OS2IP : An operation that transforms a octet string into an non-negative integer, defined in Section 4 of [@!RFC8017]. 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 refers to an error encountered in one of the Preconditions of an operation. ABORT will cause any operation to stop execution. An operation calling a subroutine that aborted must also immediately abort. + ## Notation The following notation and primitives are used: @@ -364,7 +367,7 @@ 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. -**Note** The utility functions used by the core operations of this section could fail (return INVALID). In that case, the calling operation MUST also immediately return INVALID and abort. Because under normal execution (i.e., given the correctness of the input arguments and execution of the procedure's steps), the conditions for a sub-routine to return INVALID will not be met, to increase readability the core operations do not perform explicit checks on the sub-routines results. However, an implementation should be able to catch such errors (i.e., a sub-routine returning INVALID) and abort execution. +**Note** Some of the utility functions used by the core operations of this section could fail (ABORT). In that case, the calling operation MUST also immediately abort. ### Signature Generation (Sign) @@ -412,7 +415,7 @@ Deserialization: Preconditions: -1. if L > 2^64 - 1 or length(header) > 2^64 - 1, return INVALID +1. if L > 2^64 - 1 or length(header) > 2^64 - 1, ABORT Procedure: @@ -470,7 +473,7 @@ Deserialization: Preconditions: -1. if L > 2^64 - 1 or length(header) > 2^64 - 1, return INVALID +1. if L > 2^64 - 1 or length(header) > 2^64 - 1, ABORT Procedure: @@ -545,9 +548,8 @@ Deserialization: Preconditions: -1. if L > 2^64 - 1 or length(header) > 2^64 - 1, return INVALID -2. if length(ph) > 2^64 - 1, return INVALID -3. if R > 2^64 - 1, return INVALID +1. if L > 2^64 - 1 or R > 2^64 - 1, ABORT +2. if length(header) > 2^64 - 1 or length(ph) > 2^64 - 1, ABORT Procedure: @@ -634,11 +636,10 @@ Deserialization: Preconditions: -1. if L > 2^64 - 1 or length(header) > 2^64 - 1, return INVALID -2. if length(ph) > 2^64 - 1, return INVALID -3. if R > 2^64 - 1, return INVALID -4. for i in (i1, ..., iR), if i < 1 or i > L, return INVALID -5. if length(disclosed_messages) != R, return INVALID +1. if L > 2^64 - 1 or R > 2^64 - 1, ABORT +2. if length(header) > 2^64 - 1 or length(ph) > 2^64 - 1, ABORT +3. for i in (i1, ..., iR), if i < 1 or i > L, ABORT +4. if length(disclosed_messages) != R, ABORT Procedure: @@ -662,8 +663,6 @@ Procedure: This operation returns the requested number of pseudo-random scalars, using the `get_random` operation (see [Parameters](#parameters)). The operation makes multiple calls to `get_random`. It is REQUIRED that each call will be independent from each other, as to ensure independence of the returned pseudo-random scalars. -The required length of the `get_random` output is defined as `expand_len`. Each value returned by the `get_random` function is reduced modulo the group order `r`. To avoid biased results when creating the random scalars, the output of `get_random` MUST be at least `(ceil(log2(r))+k` bytes long, where `k` is the targeted security level specified by the ciphersuite (see Section 5 in [@!I-D.irtf-cfrg-hash-to-curve] for more details). ProofGen defines `expand_len = ceil((ceil(log2(r))+k)/8)`. For both the [BLS12-381-SHAKE-256](#bls12-381-shake-256) and [BLS12-381-SHA-256](#bls12-381-sha-256) ciphersuites, `log2(r) = 255` and `k = 128` resulting to `expand_len = 48`. See [Section 5.10](#randomness-requirements) for further security considerations and requirements around the generated randomness. - **Note**: The security of the proof generation algorithm ([ProofGen](#proof-generation-proofgen)) is highly dependant on the quality of the `get_random` function. Care must be taken to ensure that a cryptographically secure pseudo-random generator is chosen, and that its outputs are not leaked to an adversary. See also [Section 5.10](#randomness-requirements) for more details. ``` @@ -678,8 +677,7 @@ Parameters: - get_random, a pseudo random function with extendable output, returning uniformly distributed pseudo random bytes. -- expand_len = ceil((ceil(log2(r))+k)/8), where r and k are defined by - the ciphersuite. +- expand_len, the expend_len value defined by the ciphersuite. Outputs: @@ -736,8 +734,7 @@ Definitions: ciphersuite_id is defined by the ciphersuite and "SIG_GENERATOR_DST_" is an ASCII string comprised of 18 bytes. -- seed_len = ceil((ceil(log2(r)) + k)/8), where r and k are defined by - the ciphersuite. +- expand_len, the expend_len value defined by the ciphersuite. Outputs: @@ -745,10 +742,10 @@ Outputs: Procedure: -1. v = expand_message(generator_seed, seed_dst, seed_len) +1. v = expand_message(generator_seed, seed_dst, expand_len) 2. n = 1 3. for i in range(1, count): -4. v = expand_message(v || I2OSP(n, 4), seed_dst, seed_len) +4. v = expand_message(v || I2OSP(n, 4), seed_dst, expand_len) 5. n = n + 1 6. generator_i = Identity_G1 7. candidate = hash_to_curve_g1(v, generator_dst) @@ -758,11 +755,11 @@ Procedure: 11. return (generator_1, ..., generator_count) ``` -# Message to Scalar +## Message to Scalar 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 [Sign](#signature-generation-sign), [Verify](#signature-verification-verify), [ProofGen](#proof-generation-proofgen) and [ProofVerify](#proof-verification-proofverify) operations. -## Message to Scalar as Hash +### Message to Scalar as Hash This operation takes an input message and maps it to a scalar value via a cryptographic hash function for the given curve. The operation takes also as an optional input a domain separation tag (dst). If a dst is not supplied, its value MUST default to the octet string returned from ciphersuite\_id || "MAP\_MSG\_TO\_SCALAR\_AS\_HASH\_", where ciphersuite\_id is the ASCII string representing the unique ID of the ciphersuite "MAP\_MSG\_TO\_SCALAR\_AS\_HASH\_" is an ASCII string comprised of 26 bytes. @@ -779,23 +776,24 @@ Inputs: Outputs: -- msg_scalar, a scalar value. +- msg_scalar, a scalar. + +Preconditions: + +1. if length(msg) > 2^64 - 1 or length(dst) > 255, ABORT Procedure: -1. if length(msg) > 2^64 - 1 or length(dst) > 255 return INVALID -2. return hash_to_scalar(msg, dst) +1. return hash_to_scalar(msg, dst) ``` ## Hash to Scalar This operation describes how to hash an arbitrary octet string to `n` 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 hash a message to a scalar that would be passed as input to the [Sign](#sisignature-generation-signgn), [Verify](#signature-verification-verify), [ProofGen](#proof-generation-proofgen) and [ProofVerify](#proof-verification-proofverify) functions, one must use [MapMessageToScalarAsHash](#mapmessagetoscalar) instead. -This operation makes use of expand\_message defined in [@!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). 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). Note however, that the hash\_to\_curve document, makes use of hash\_to\_field with the target group being the multiplicative group of integers mod p (Fp). For this reason, we don’t directly use hash\_to\_field here, rather we define a similar operation (hash\_to\_scalar), making direct use of the expand\_message function, that will be defined by the hash-to-curve suite used (i.e., either expand\_message\_xmd or expand\_message\_xof). 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). - The operation takes as input an octet string representing the message to hash (msg), the number of the scalars to return (count) as well as an optional domain separation tag (dst). The length of the dst MUST be less than 255 octets. See section 5.3.3 of [@!I-D.irtf-cfrg-hash-to-curve] for guidance on using larger dst values. If a dst is not supplied, its value MUST default to the octet string returned from ciphersuite\_id || "H2S\_", where ciphersuite\_id is the octet string representing the unique ID of the ciphersuite and "H2S_" is an ASCII string comprised of 4 bytes. -**Note** It is possible that the `hash_to_scalar` procedure will return an error, if the underlying `expand_message` operation aborts. See [@!I-D.irtf-cfrg-hash-to-curve], Section 5.3, for more details on the cases that `expand_message` will abort (note that the input term `len_in_bytes` of `expand_message` in the Hash-to-Curve document equals `count * expand_len` in our case). +**Note** This operation makes use of `expand_message` defined in [@!I-D.irtf-cfrg-hash-to-curve]. The operation `expand_message` may fail (abort). In that case, `hash_to_scalar` MUST also ABORT. ``` hashed_scalar = hash_to_scalar(msg_octets, dst) @@ -814,27 +812,22 @@ Parameters: ciphersuite. - expand_message, the expand_message operation defined by the suite specified by the hash_to_curve_suite parameter. +- expand_len, the expend_len value defined by the ciphersuite. -Definitions: +Outputs: -- expand_len = ceil((ceil(log2(r))+k)/8), where r and k are defined by - the ciphersuite. +- hashed_scalar, a scalar. -Outputs: +Precoditions: -- hashed_scalar, a non-zero scalar mod r. +- if len(dsg) > 255, ABORT Procedure: -1. counter = 0 -2. hashed_scalar = 0 -3. while hashed_scalar == 0: -4. if counter > 255, return INVALID -5. msg_prime = msg_octets || I2OSP(counter, 1) -6. uniform_bytes = expand_message(msg_prime, dst, expand_len) -7. hashed_scalar = OS2IP(uniform_bytes) mod r -8. counter = counter + 1 -9. return hashed_scalar +1. msg_prime = msg_octets || I2OSP(counter, 1) +2. uniform_bytes = expand_message(msg_prime, dst, expand_len) +3. hashed_scalar = OS2IP(uniform_bytes) mod r +4. return hashed_scalar ``` ## Domain Calculation @@ -866,7 +859,7 @@ Parameters: Outputs: -- domain, a scalar value or INVALID. +- domain, a scalar. Deserialization: @@ -875,7 +868,7 @@ Deserialization: Preconditions: -1. if length(header) > 2^64 - 1 or L > 2^64 - 1, return INVALID +1. if length(header) > 2^64 - 1 or L > 2^64 - 1, ABORT Procedure: @@ -909,7 +902,7 @@ Inputs: Outputs: -- challenge, a scalar or INVALID. +- challenge, a scalar. Deserialization: @@ -919,9 +912,9 @@ Deserialization: Preconditions: -1. if R > 2^64 - 1 or R != length(msg_array), return INVALID -2. if length(ph) > 2^64 - 1, return INVALID -3. for i in i_array, if i > 2^64 - 1, return INVALID +1. if R > 2^64 - 1 or R != length(msg_array), ABORT +2. if length(ph) > 2^64 - 1, ABORT +3. for i in i_array, if i > 2^64 - 1, ABORT Procedure: @@ -929,6 +922,7 @@ Procedure: 2. c_octs = serialize(c_array) 3. return hash_to_scalar(c_octs || I2OSP(length(ph), 8) || ph) ``` + **Note**: Similarly to the header value in [Domain Calculation](#domain-calculation), if the presentation header (ph) is not supplied in `calculate_challenge`, 8 bytes representing a length of 0 (i.e., `0x0000000000000000`), must still be appended after the `c_octs` value, during the concatenation step of the above procedure (step 3). ## Serialization @@ -1241,7 +1235,7 @@ The parameters that each ciphersuite needs to define are generally divided into - hash\_to\_curve\_suite: The hash-to-curve ciphersuite id, in the form defined in [@!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 [Notation](#notation) section) and the expand\_message (either expand\_message\_xmd or expand\_message\_xof) operations used in this document. -- expand\_len: The length to expand a message to, during hash\_to\_scalar in (#hash-to-scalar). This length MUST be defined in a way that will not cause the expand\_message operation specified by the hash\_to\_curve\_suite to abort. It MUST also be defined to be larger than `ceil((ceil(log2(r))+k)/8)`, where `log2(r)` and `k` are defined by each ciphersuite. If both of those restrictions cannot be satisfied, a different hash\_to\_curve suite and curve may be chosen. +- 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 in [@!I-D.irtf-cfrg-hash-to-curve] for a more detailed explanation of this definition). - P1: A fixed point in the G1 subgroup. From af7e05d512cbd25b8aaf72e6acd8716f0aa3969b Mon Sep 17 00:00:00 2001 From: Vasilis Kalos Date: Wed, 14 Jun 2023 21:38:39 +0300 Subject: [PATCH 05/13] rm checks from calculate_generators --- draft-irtf-cfrg-bbs-signatures.md | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/draft-irtf-cfrg-bbs-signatures.md b/draft-irtf-cfrg-bbs-signatures.md index 4fad80e5..27f93e41 100644 --- a/draft-irtf-cfrg-bbs-signatures.md +++ b/draft-irtf-cfrg-bbs-signatures.md @@ -700,7 +700,7 @@ As an optimization, implementations MAY cache the result of `create_generators` For example, an application can save 100 generator points `H_1, H_2, ..., H_100` returned from `create_generators(100)`. Then if one of the core operations needs 30 of them, the application instead of calling `create_generators` again, can just retrieve the 30 first generators `H_1, H_2, ..., H_30` from the cache instead, in the same order they where originally created (starting from the first one). -The values `n` and `v` MAY also be cached in order to efficiently extend an existing list of cached generator points. +The value of `v` MAY also be cached in order to efficiently extend an existing list of cached generator points. ``` generators = create_generators(count) @@ -742,17 +742,11 @@ Outputs: Procedure: -1. v = expand_message(generator_seed, seed_dst, expand_len) -2. n = 1 -3. for i in range(1, count): -4. v = expand_message(v || I2OSP(n, 4), seed_dst, expand_len) -5. n = n + 1 -6. generator_i = Identity_G1 -7. candidate = hash_to_curve_g1(v, generator_dst) -8. if candidate in (generator_1, ..., generator_i, P_1): -9. go back to step 4 -10. generator_i = candidate -11. return (generator_1, ..., generator_count) +1. v = expand_message(generator_seed, seed_dst, expand_len) +2. for i in range(1, count): +3. v = expand_message(v || I2OSP(i, 4), seed_dst, expand_len) +4. generator_i = hash_to_curve_g1(v, generator_dst) +5. return (generator_1, ..., generator_count) ``` ## Message to Scalar From 7cf4b06a6c74d43b357445ac898759fc73a223d8 Mon Sep 17 00:00:00 2001 From: Vasilis Kalos Date: Mon, 19 Jun 2023 19:00:12 +0300 Subject: [PATCH 06/13] fix hash to scalar --- draft-irtf-cfrg-bbs-signatures.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/draft-irtf-cfrg-bbs-signatures.md b/draft-irtf-cfrg-bbs-signatures.md index 27f93e41..ab0dc814 100644 --- a/draft-irtf-cfrg-bbs-signatures.md +++ b/draft-irtf-cfrg-bbs-signatures.md @@ -814,14 +814,12 @@ Outputs: Precoditions: -- if len(dsg) > 255, ABORT +- if length(dsg) > 255, ABORT Procedure: -1. msg_prime = msg_octets || I2OSP(counter, 1) -2. uniform_bytes = expand_message(msg_prime, dst, expand_len) -3. hashed_scalar = OS2IP(uniform_bytes) mod r -4. return hashed_scalar +1. uniform_bytes = expand_message(msg_octets, dst, expand_len) +2. return OS2IP(uniform_bytes) mod r ``` ## Domain Calculation From 98676655e95322447c27f9be46e3410601f81e8f Mon Sep 17 00:00:00 2001 From: Vasilis Kalos Date: Mon, 19 Jun 2023 19:32:35 +0300 Subject: [PATCH 07/13] preconditions -> abort if --- draft-irtf-cfrg-bbs-signatures.md | 46 +++++++++++++++---------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/draft-irtf-cfrg-bbs-signatures.md b/draft-irtf-cfrg-bbs-signatures.md index ab0dc814..4b33b573 100644 --- a/draft-irtf-cfrg-bbs-signatures.md +++ b/draft-irtf-cfrg-bbs-signatures.md @@ -167,7 +167,7 @@ OS2IP : An operation that transforms a octet string into an non-negative integer, defined in Section 4 of [@!RFC8017]. 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 refers to an error encountered in one of the Preconditions of an operation. ABORT will cause any operation to stop execution. An operation calling a subroutine that aborted must also immediately 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 of the initial constrains 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. ## Notation @@ -413,9 +413,9 @@ Deserialization: 1. L = length(messages) 2. (msg_1, ..., msg_L) = messages -Preconditions: +ABORT if: -1. if L > 2^64 - 1 or length(header) > 2^64 - 1, ABORT +1. L > 2^64 - 1 or length(header) > 2^64 - 1 Procedure: @@ -471,9 +471,9 @@ Deserialization: 6. L = length(messages) 7. (msg_1, ..., msg_L) = messages -Preconditions: +ABORT if: -1. if L > 2^64 - 1 or length(header) > 2^64 - 1, ABORT +1. L > 2^64 - 1 or length(header) > 2^64 - 1 Procedure: @@ -546,10 +546,10 @@ Deserialization: 11. (msg_i1, ..., msg_iR) = (messages[i1], ..., messages[iR]) 12. (msg_j1, ..., msg_jU) = (messages[j1], ..., messages[jU]) -Preconditions: +ABORT if: -1. if L > 2^64 - 1 or R > 2^64 - 1, ABORT -2. if length(header) > 2^64 - 1 or length(ph) > 2^64 - 1, ABORT +1. L > 2^64 - 1 or R > 2^64 - 1 +2. length(header) > 2^64 - 1 or length(ph) > 2^64 - 1 Procedure: @@ -634,12 +634,12 @@ Deserialization: 11. (msg_i1, ..., msg_iR) = disclosed_messages 12. (m^_j1, ...., m^_jU) = commitments -Preconditions: +ABORT if: -1. if L > 2^64 - 1 or R > 2^64 - 1, ABORT -2. if length(header) > 2^64 - 1 or length(ph) > 2^64 - 1, ABORT -3. for i in (i1, ..., iR), if i < 1 or i > L, ABORT -4. if length(disclosed_messages) != R, ABORT +1. L > 2^64 - 1 or R > 2^64 - 1 +2. length(header) > 2^64 - 1 or length(ph) > 2^64 - 1 +3. for i in (i1, ..., iR), i < 1 or i > L +4. length(disclosed_messages) != R Procedure: @@ -772,9 +772,9 @@ Outputs: - msg_scalar, a scalar. -Preconditions: +ABORT if: -1. if length(msg) > 2^64 - 1 or length(dst) > 255, ABORT +1. length(msg) > 2^64 - 1 or length(dst) > 255 Procedure: @@ -858,9 +858,9 @@ Deserialization: 1. L = length(H_Points) 2. (H_1, ..., H_L) = H_Points -Preconditions: +ABORT if: -1. if length(header) > 2^64 - 1 or L > 2^64 - 1, ABORT +1. length(header) > 2^64 - 1 or L > 2^64 - 1 Procedure: @@ -902,11 +902,11 @@ Deserialization: 2. (i1, ..., iR) = i_array 3. (msg_i1, ..., msg_iR) = msg_array -Preconditions: +ABORT if: -1. if R > 2^64 - 1 or R != length(msg_array), ABORT -2. if length(ph) > 2^64 - 1, ABORT -3. for i in i_array, if i > 2^64 - 1, ABORT +1. R > 2^64 - 1 or R != length(msg_array) +2. length(ph) > 2^64 - 1 +3. for i in i_array, i > 2^64 - 1 Procedure: @@ -1377,9 +1377,9 @@ Outputs: - mocked_random_scalars, a list of "count" pseudo random scalars -Preconditions: +ABORT if: -1. if count * expand_len > 65535, return INVALID +1. count * expand_len > 65535 Procedure: From 3f0ed15536376b1a70d226975835da2097659989 Mon Sep 17 00:00:00 2001 From: Vasilis Kalos Date: Mon, 19 Jun 2023 19:52:51 +0300 Subject: [PATCH 08/13] fix typo --- draft-irtf-cfrg-bbs-signatures.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/draft-irtf-cfrg-bbs-signatures.md b/draft-irtf-cfrg-bbs-signatures.md index 4b33b573..3c7e9904 100644 --- a/draft-irtf-cfrg-bbs-signatures.md +++ b/draft-irtf-cfrg-bbs-signatures.md @@ -812,9 +812,9 @@ Outputs: - hashed_scalar, a scalar. -Precoditions: +ABORT if: -- if length(dsg) > 255, ABORT +- length(dst) > 255 Procedure: From d16bd791290e066d1b7a28aad7b5e09c760583db Mon Sep 17 00:00:00 2001 From: Vasilis Kalos Date: Mon, 19 Jun 2023 20:36:15 +0300 Subject: [PATCH 09/13] rm unused parameters --- draft-irtf-cfrg-bbs-signatures.md | 1 - 1 file changed, 1 deletion(-) diff --git a/draft-irtf-cfrg-bbs-signatures.md b/draft-irtf-cfrg-bbs-signatures.md index 3c7e9904..5a5cd150 100644 --- a/draft-irtf-cfrg-bbs-signatures.md +++ b/draft-irtf-cfrg-bbs-signatures.md @@ -720,7 +720,6 @@ Parameters: specified by the hash_to_curve_suite parameter. - generator_seed, an octet string. A seed value selected by the ciphersuite. -- P1, fixed point of G1, defined by the ciphersuite. Definitions: From bfb7bd631a10f8d33f3fee46f25e2bdcb87469bf Mon Sep 17 00:00:00 2001 From: Vasilis Kalos Date: Tue, 20 Jun 2023 12:29:35 +0300 Subject: [PATCH 10/13] Andrews suggestions: 1/2 Co-authored-by: Andrew Whitehead --- draft-irtf-cfrg-bbs-signatures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/draft-irtf-cfrg-bbs-signatures.md b/draft-irtf-cfrg-bbs-signatures.md index 5a5cd150..7561cfba 100644 --- a/draft-irtf-cfrg-bbs-signatures.md +++ b/draft-irtf-cfrg-bbs-signatures.md @@ -167,7 +167,7 @@ OS2IP : An operation that transforms a octet string into an non-negative integer, defined in Section 4 of [@!RFC8017]. 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 of the initial constrains 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. +: 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. ## Notation From 2dca3f3ef900e932f310dea58094f7c693a66e3e Mon Sep 17 00:00:00 2001 From: Vasilis Kalos Date: Tue, 20 Jun 2023 13:25:11 +0300 Subject: [PATCH 11/13] Andrews suggestions: 2/2 --- draft-irtf-cfrg-bbs-signatures.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/draft-irtf-cfrg-bbs-signatures.md b/draft-irtf-cfrg-bbs-signatures.md index 7561cfba..be7e37e3 100644 --- a/draft-irtf-cfrg-bbs-signatures.md +++ b/draft-irtf-cfrg-bbs-signatures.md @@ -564,7 +564,7 @@ Procedure: 9. Bbar = B * r1 - Abar * e 10. C = Bbar * r2 + Abar * r3 + H_j1 * m~_j1 + ... + H_jU * m~_jU 11. c = calculate_challenge(Abar, Bbar, C, (i1, ..., iR), - (msg_i1, ..., msg_iR), domain, ph) + (msg_i1, ..., msg_iR), domain, ph) 12. r4 = - r1^-1 (mod r) 13. r2^ = r2 + r4 * c (mod r) 14. r3^ = r3 + e * r4 * c (mod r) @@ -651,7 +651,7 @@ Procedure: 6. D = P1 + Q_1 * domain + H_i1 * msg_i1 + ... + H_iR * msg_iR 7. C = Bbar * r2^ + Abar * r3^ + H_j1 * m^_j1 + ... + H_jU * m^_jU + D * c 8. cv = calculate_challenge(Abar, Bbar, C, (i1, ..., iR), - (msg_i1, ..., msg_iR), domain, ph) + (msg_i1, ..., msg_iR), domain, ph) 9. if c != cv, return INVALID 10. if e(Abar, W) * e(Bbar, -P2) != Identity_GT, return INVALID 11. return VALID @@ -677,7 +677,7 @@ Parameters: - get_random, a pseudo random function with extendable output, returning uniformly distributed pseudo random bytes. -- expand_len, the expend_len value defined by the ciphersuite. +- expand_len, defined by the ciphersuite. Outputs: @@ -733,7 +733,7 @@ Definitions: ciphersuite_id is defined by the ciphersuite and "SIG_GENERATOR_DST_" is an ASCII string comprised of 18 bytes. -- expand_len, the expend_len value defined by the ciphersuite. +- expand_len, defined by the ciphersuite. Outputs: @@ -805,7 +805,7 @@ Parameters: ciphersuite. - expand_message, the expand_message operation defined by the suite specified by the hash_to_curve_suite parameter. -- expand_len, the expend_len value defined by the ciphersuite. +- expand_len, defined by the ciphersuite. Outputs: @@ -1367,8 +1367,7 @@ Parameters: - expand_message, the expand_message operation defined by the ciphersuite. -- expand_len = ceil((ceil(log2(r))+k)/8), where r and k are defined by - the ciphersuite. +- expand_len, defined by the ciphersuite. - dst = ciphersuite_id || "MOCK_RANDOM_SCALARS_DST_", where ciphersuite_id is defined by the ciphersuite. From 9df3b74fc8da8544de772f82fde21ac4ff35ca98 Mon Sep 17 00:00:00 2001 From: Vasilis Kalos Date: Tue, 20 Jun 2023 13:50:26 +0300 Subject: [PATCH 12/13] rm unnecessary ABORT conditions --- draft-irtf-cfrg-bbs-signatures.md | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/draft-irtf-cfrg-bbs-signatures.md b/draft-irtf-cfrg-bbs-signatures.md index be7e37e3..42f5f031 100644 --- a/draft-irtf-cfrg-bbs-signatures.md +++ b/draft-irtf-cfrg-bbs-signatures.md @@ -413,10 +413,6 @@ Deserialization: 1. L = length(messages) 2. (msg_1, ..., msg_L) = messages -ABORT if: - -1. L > 2^64 - 1 or length(header) > 2^64 - 1 - Procedure: 1. (Q_1, H_1, ..., H_L) = create_generators(L+1) @@ -471,10 +467,6 @@ Deserialization: 6. L = length(messages) 7. (msg_1, ..., msg_L) = messages -ABORT if: - -1. L > 2^64 - 1 or length(header) > 2^64 - 1 - Procedure: 1. (Q_1, H_1, ..., H_L) = create_generators(L+1) @@ -548,8 +540,7 @@ Deserialization: ABORT if: -1. L > 2^64 - 1 or R > 2^64 - 1 -2. length(header) > 2^64 - 1 or length(ph) > 2^64 - 1 +1. for i in (i1, ..., iR), i < 1 or i > L Procedure: @@ -636,10 +627,8 @@ Deserialization: ABORT if: -1. L > 2^64 - 1 or R > 2^64 - 1 -2. length(header) > 2^64 - 1 or length(ph) > 2^64 - 1 -3. for i in (i1, ..., iR), i < 1 or i > L -4. length(disclosed_messages) != R +1. for i in (i1, ..., iR), i < 1 or i > L +2. length(disclosed_messages) != R Procedure: @@ -739,6 +728,10 @@ Outputs: - generators, an array of generators. +ABORT if: + +1. count > 2^64 - 1 + Procedure: 1. v = expand_message(generator_seed, seed_dst, expand_len) @@ -905,7 +898,6 @@ ABORT if: 1. R > 2^64 - 1 or R != length(msg_array) 2. length(ph) > 2^64 - 1 -3. for i in i_array, i > 2^64 - 1 Procedure: From f466da9d5931d987e2439c0087ae0fc64f8f3627 Mon Sep 17 00:00:00 2001 From: Vasilis Kalos Date: Tue, 20 Jun 2023 13:51:15 +0300 Subject: [PATCH 13/13] fix max no of generators --- draft-irtf-cfrg-bbs-signatures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/draft-irtf-cfrg-bbs-signatures.md b/draft-irtf-cfrg-bbs-signatures.md index 42f5f031..5aa67a69 100644 --- a/draft-irtf-cfrg-bbs-signatures.md +++ b/draft-irtf-cfrg-bbs-signatures.md @@ -736,7 +736,7 @@ Procedure: 1. v = expand_message(generator_seed, seed_dst, expand_len) 2. for i in range(1, count): -3. v = expand_message(v || I2OSP(i, 4), seed_dst, expand_len) +3. v = expand_message(v || I2OSP(i, 8), seed_dst, expand_len) 4. generator_i = hash_to_curve_g1(v, generator_dst) 5. return (generator_1, ..., generator_count) ```