From f1058ccfa99de841ac339cf84a7e353d56ec93c9 Mon Sep 17 00:00:00 2001 From: Conrado Gouvea Date: Thu, 25 Aug 2022 15:37:10 -0300 Subject: [PATCH] update to spec V8 --- zip-frost.rst | 103 ++++++++++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 49 deletions(-) diff --git a/zip-frost.rst b/zip-frost.rst index bc7d7e81..7b5b8b72 100644 --- a/zip-frost.rst +++ b/zip-frost.rst @@ -79,7 +79,7 @@ shielded transaction: - The zero-knowledge proof for the transaction is created with the randomizer as an auxiliary (secret) input, among others. -When employing re-randomized FROST as specified in this ZIP, the goal is to +When employing re-randomizable FROST as specified in this ZIP, the goal is to split the spend authorization private key :math:`\mathsf{ask}` among multiple possible signers. This means that the proof generation will still be generated by a single participant, likely the one that created the transaction in the first @@ -123,8 +123,8 @@ The types Scalar, Element, and G are defined in #[frost-primeordergroup]_, as we as the notation for elliptic-curve arithmetic, which uses the additive notation. -Re-randomized FROST -------------------- +Re-randomizable FROST +--------------------- To add re-randomization to FROST, follow the specification [#FROST]_ with the following modifications. @@ -158,7 +158,7 @@ A new helper function is defined, which computes :math:`\mathsf{RedDSA.GenRandom def randomizer_generate(): randomizer_input = random_bytes(64) - return H2(randomizer_input) + return H3(randomizer_input) Binding Factor Computation @@ -168,18 +168,27 @@ The `compute_binding_factor` function is changed to receive the `randomizer` as follows: :: Inputs: - - encoded_commitment_list, an encoded commitment list (as computed - by encode_group_commitment_list) + - commitment_list = [(i, hiding_nonce_commitment_i, binding_nonce_commitment_i), ...], + a list of commitments issued by each signer, where each element in the list + indicates the signer identifier i and their two commitment Element values + (hiding_nonce_commitment_i, binding_nonce_commitment_i). This list MUST be sorted + in ascending order by signer identifier. - msg, the message to be signed. - randomizer, the randomizer Scalar. - Outputs: A Scalar representing the binding factor + Outputs: A list of (identifier, Scalar) tuples representing the binding factors. - def compute_binding_factor(encoded_commitment_list, msg, randomizer): - msg_hash = H3(msg) - rho_input = encoded_commitment_list || msg_hash || G.SerializeScalar(randomizer) - binding_factor = H1(rho_input) - return binding_factor + def compute_binding_factors(commitment_list, msg, randomizer): + msg_hash = H4(msg) + encoded_commitment_hash = H5(encode_group_commitment_list(commitment_list)) + rho_input_prefix = msg_hash || encoded_commitment_hash || G.SerializeScalar(randomizer) + + binding_factor_list = [] + for (identifier, hiding_nonce_commitment, binding_nonce_commitment) in commitment_list: + rho_input = rho_input_prefix || encode_uint16(identifier) + binding_factor = H1(rho_input) + binding_factor_list.append((identifier, binding_factor)) + return binding_factor_list Round One - Commitment @@ -206,8 +215,7 @@ The `sign` function is changed to receive `randomizer` and incorporate it into t computation of the binding factor. It is specified as the following: :: Inputs: - - identifier, Identifier i of the signer. - Note: FROST spec requires that identifier will never equal 0. + - identifier, Identifier i of the signer. Note identifier will never equal 0. - sk_i, Signer secret key share, a Scalar. - group_public_key, public key corresponding to the group signing key, an Element in G. @@ -228,18 +236,16 @@ computation of the binding factor. It is specified as the following: :: # Compute the randomized group public key randomized_group_public_key = group_public_key + G * randomizer - # Encode the commitment list - encoded_commitments = encode_group_commitment_list(commitment_list) - - # Compute the binding factor - binding_factor = compute_binding_factor(encoded_commitments, msg, randomizer) + # Compute the binding factor(s) + binding_factor_list = compute_binding_factors(commitment_list, msg) + binding_factor = binding_factor_for_participant(binding_factor_list, identifier, randomizer) # Compute the group commitment - group_commitment = compute_group_commitment(commitment_list, binding_factor) + group_commitment = compute_group_commitment(commitment_list, binding_factor_list) # Compute Lagrange coefficient participant_list = participants_from_commitment_list(commitment_list) - lambda_i = derive_lagrange_coefficient(identifier, participant_list) + lambda_i = derive_lagrange_coefficient(Scalar(identifier), participant_list) # Compute the per-message challenge challenge = compute_challenge(group_commitment, randomized_group_public_key, msg) @@ -258,8 +264,7 @@ The `verify_signature_share` is changed to incorporate the randomizer, as follows: :: Inputs: - - identifier, Identifier i of the signer. - Note: identifier will never equal 0. + - identifier, Identifier i of the signer. Note: identifier MUST never equal 0. - PK_i, the public key for the ith signer, where PK_i = G.ScalarBaseMult(sk_i), an Element in G - comm_i, pair of Element values in G (hiding_nonce_commitment, binding_nonce_commitment) @@ -284,29 +289,27 @@ as follows: :: # Compute the randomized group public key randomized_group_public_key = group_public_key + G * randomizer - # Encode the commitment list - encoded_commitments = encode_group_commitment_list(commitment_list) - - # Compute the binding factor - binding_factor = compute_binding_factor(encoded_commitments, msg, randomizer) + # Compute the binding factors + binding_factor_list = compute_binding_factors(commitment_list, msg, randomizer) + binding_factor = binding_factor_for_participant(binding_factor_list, identifier) # Compute the group commitment - group_commitment = compute_group_commitment(commitment_list, binding_factor) + group_commitment = compute_group_commitment(commitment_list, binding_factor_list) # Compute the commitment share (hiding_nonce_commitment, binding_nonce_commitment) = comm_i - comm_share = hiding_nonce_commitment + (binding_nonce_commitment * binding_factor) + comm_share = hiding_nonce_commitment + G.ScalarMult(binding_nonce_commitment, binding_factor) # Compute the challenge challenge = compute_challenge(group_commitment, randomized_group_public_key, msg) # Compute Lagrange coefficient participant_list = participants_from_commitment_list(commitment_list) - lambda_i = derive_lagrange_coefficient(identifier, participant_list) + lambda_i = derive_lagrange_coefficient(Scalar(identifier), participant_list) # Compute relation values l = G.ScalarBaseMult(sig_share_i) - r = comm_share + ((challenge * lambda_i) * PK_i) + r = comm_share + G.ScalarMult(PK_i, challenge * lambda_i) return l == r @@ -315,8 +318,7 @@ The `aggregate` function is changed to incorporate the randomizer as follows: :: Inputs: - group_commitment, the group commitment returned by compute_group_commitment, an Element in G. - - sig_shares, a set of signature shares z_i, Scalar values, for each signer - that participated in Round One, + - sig_shares, a set of signature shares z_i, Scalar values, for each signer, of length NUM_SIGNERS, where MIN_SIGNERS <= NUM_SIGNERS <= MAX_SIGNERS. - group_public_key, public key corresponding to the group signing key, - challenge, the challenge returned by compute_challenge, a Scalar. @@ -348,8 +350,8 @@ Authorization Signatures as specified in [#protocol-concretespendauthsig]_. - Order: 6554484396890773809930967563523245729705921265872317281365359162392183254199 (see [#protocol-jubjub]_) - Identity: as defined in [#protocol-jubjub]_ - - RandomScalar: Implemented by generating a random 64-byte string and invoking - DeserializeScalar on the result + - RandomScalar(): Implemented by returning a uniformly random Scalar in the range \[0, `G.Order()` - 1\]. + Refer to {{frost-randomscalar}} for implementation guidance. - RandomNonZeroScalar: Implemented by generating a random 32-byte string that is not equal to the all-zero string and invoking DeserializeScalar on the result. - SerializeElement(P): Implemented as :math:`\mathsf{repr}_\mathbb{J}(P)` as defined in [#protocol-jubjub]_ @@ -359,7 +361,7 @@ Authorization Signatures as specified in [#protocol-concretespendauthsig]_. of the Scalar value. - DeserializeScalar: Implemented by attempting to deserialize a Scalar from a little-endian 32-byte string. This function can fail if the input does not represent a Scalar - in the range \[0, G.Order() - 1\]. + in the range \[0, `G.Order()` - 1\]. - Hash (`H`): BLAKE2b-512 [#BLAKE]_ (BLAKE2b with 512-bit output and 16-byte personalization string), and Nh = 64. @@ -372,10 +374,11 @@ Authorization Signatures as specified in [#protocol-concretespendauthsig]_. modulo L = 6554484396890773809930967563523245729705921265872317281365359162392183254199. (This is equivalent to :math:`\mathsf{H}^\circledast(m)`, as defined in [#protocol-concretereddsa]_ parametrized with [#protocol-jubjub]_.) - - H3(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubD", m) - - H4(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubN", m), interpreting + - H3(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubN", m), interpreting the 64 bytes as a little-endian integer, and reducing the resulting integer modulo L = 6554484396890773809930967563523245729705921265872317281365359162392183254199. + - H4(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubM", m) + - H5(m): Implemented by computing BLAKE2b-512("FROST_RedJubjubC", m) FROST(Pallas, BLAKE2b-512) @@ -389,8 +392,8 @@ Authorization Signatures as specified in [#protocol-concretespendauthsig]_. - Order: 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 (see [#protocol-pallasandvesta]_) - Identity: as defined in [#protocol-pallasandvesta]_ - - RandomScalar: Implemented by generating a random 64-byte string and invoking - DeserializeScalar on the result + - RandomScalar(): Implemented by returning a uniformly random Scalar in the range \[0, `G.Order()` - 1\]. + Refer to {{frost-randomscalar}} for implementation guidance. - RandomNonZeroScalar: Implemented by generating a random 32-byte string that is not equal to the all-zero string and invoking DeserializeScalar on the result. - SerializeElement(P): Implemented as :math:`\mathsf{repr}_\mathbb{P}(P)` as defined in [#protocol-pallasandvesta]_ @@ -400,7 +403,7 @@ Authorization Signatures as specified in [#protocol-concretespendauthsig]_. of the Scalar value. - DeserializeScalar: Implemented by attempting to deserialize a Scalar from a little-endian 32-byte string. This function can fail if the input does not represent a Scalar - in the range \[0, G.Order() - 1\]. + in the range \[0, `G.Order()` - 1\]. - Hash (`H`): BLAKE2b-512 [#BLAKE]_ (BLAKE2b with 512-bit output and 16-byte personalization string), and Nh = 64. @@ -413,10 +416,11 @@ Authorization Signatures as specified in [#protocol-concretespendauthsig]_. modulo L = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001. (This is equivalent to :math:`\mathsf{H}^\circledast(m)`, as defined in [#protocol-concretereddsa]_ parametrized with [#protocol-pallasandvesta]_.) - - H3(m): Implemented by computing BLAKE2b-512("FROST_RedPallasD", m). - - H4(m): Implemented by computing BLAKE2b-512("FROST_RedPallasN", m), interpreting + - H3(m): Implemented by computing BLAKE2b-512("FROST_RedPallasN", m), interpreting the 64 bytes as a little-endian integer, and reducing the resulting integer modulo L = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001. + - H4(m): Implemented by computing BLAKE2b-512("FROST_RedPallasM", m). + - H5(m): Implemented by computing BLAKE2b-512("FROST_RedPallasC", m). Reference implementation @@ -430,11 +434,12 @@ References .. [#BLAKE] `BLAKE2: simpler, smaller, fast as MD5 `_ .. [#RFC2119] `RFC 2119: Key words for use in RFCs to Indicate Requirement Levels `_ -.. [#FROST] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST `_ -.. [#frost-protocol] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Section 5: Two-Round FROST Signing Protocol `_ -.. [#frost-removingcoordinator] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Section 7.3: Removing the Coordinator Role `_ -.. [#frost-primeordergroup] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Section 3.1: Prime-Order Group `_ -.. [#frost-tdkg] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Appendix B: Trusted Dealer Key Generation `_ +.. [#FROST] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST `_ +.. [#frost-protocol] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Section 5: Two-Round FROST Signing Protocol `_ +.. [#frost-removingcoordinator] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Section 7.3: Removing the Coordinator Role `_ +.. [#frost-primeordergroup] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Section 3.1: Prime-Order Group `_ +.. [#frost-tdkg] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Appendix B: Trusted Dealer Key Generation `_ +.. [#frost-randomscalar] `Draft RFC: Two-Round Threshold Schnorr Signatures with FROST. Appendix C: Random Scalar Generation `_ .. [#protocol-concretereddsa] `Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 5.4.7: RedDSA, RedJubjub, and RedPallas `_ .. [#protocol-concretespendauthsig] `Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 5.4.7.1: Spend Authorization Signature (Sapling and Orchard) `_ .. [#protocol-spendauthsig] `Zcash Protocol Specification, Version 2022.3.4 [NU5]. Section 4.15: Spend Authorization Signature (Sapling and Orchard) `_