From 95d926fb1e9f7269c23c03aaf4a3af28e750e3f4 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Thu, 11 May 2023 15:05:35 +0100 Subject: [PATCH] Adds prehashed message variant of EcDSA (https://github.com/AztecProtocol/barretenberg/pull/437) * verification takes a pre-hashed message : Note: if len(hash) > 32 bytes, then bigfield will fail * use hashed_message when generating signature * modify acir structure and function to now use prehashed variant * message -> hashed_message --- .../dsl/acir_format/ecdsa_secp256k1.cpp | 16 ++++---- .../dsl/acir_format/ecdsa_secp256k1.hpp | 10 ++--- .../dsl/acir_format/ecdsa_secp256k1.test.cpp | 12 ++++-- .../stdlib/encryption/ecdsa/ecdsa.hpp | 4 ++ .../stdlib/encryption/ecdsa/ecdsa_impl.hpp | 37 +++++++++++++++---- 5 files changed, 54 insertions(+), 25 deletions(-) diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp index d4ec3e235d6..5a9caaa6997 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp @@ -89,7 +89,7 @@ void create_ecdsa_verify_constraints(Composer& composer, const EcdsaSecp256k1Con auto new_sig = ecdsa_convert_signature(composer, input.signature); - auto message = ecdsa_vector_of_bytes_to_byte_array(composer, input.message); + auto message = ecdsa_vector_of_bytes_to_byte_array(composer, input.hashed_message); auto pub_key_x_byte_arr = ecdsa_vector_of_bytes_to_byte_array(composer, input.pub_x_indices); auto pub_key_y_byte_arr = ecdsa_vector_of_bytes_to_byte_array(composer, input.pub_y_indices); @@ -113,16 +113,16 @@ void create_ecdsa_verify_constraints(Composer& composer, const EcdsaSecp256k1Con pub_key_x_byte_arr[i].assert_equal(field_ct::from_witness_index(&composer, input.pub_x_indices[i])); pub_key_y_byte_arr[i].assert_equal(field_ct::from_witness_index(&composer, input.pub_y_indices[i])); } - for (size_t i = 0; i < input.message.size(); ++i) { - message[i].assert_equal(field_ct::from_witness_index(&composer, input.message[i])); + for (size_t i = 0; i < input.hashed_message.size(); ++i) { + message[i].assert_equal(field_ct::from_witness_index(&composer, input.hashed_message[i])); } bool_ct signature_result = - stdlib::ecdsa::verify_signature_noassert(message, public_key, sig); + stdlib::ecdsa::verify_signature_prehashed_message_noassert(message, public_key, sig); bool_ct signature_result_normalized = signature_result.normalize(); composer.assert_equal(signature_result_normalized.witness_index, input.result); } diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp index 55d8f6c16dc..93a87d386c6 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp @@ -5,10 +5,8 @@ namespace acir_format { struct EcdsaSecp256k1Constraint { - // This is just a bunch of bytes - // which need to be interpreted as a string - // Note this must be a bunch of bytes - std::vector message; + // This is the byte representation of the hashed message. + std::vector hashed_message; // This is the supposed public key which signed the // message, giving rise to the signature. @@ -33,7 +31,7 @@ void create_ecdsa_verify_constraints(Composer& composer, const EcdsaSecp256k1Con template inline void read(B& buf, EcdsaSecp256k1Constraint& constraint) { using serialize::read; - read(buf, constraint.message); + read(buf, constraint.hashed_message); read(buf, constraint.signature); read(buf, constraint.pub_x_indices); read(buf, constraint.pub_y_indices); @@ -43,7 +41,7 @@ template inline void read(B& buf, EcdsaSecp256k1Constraint& constra template inline void write(B& buf, EcdsaSecp256k1Constraint const& constraint) { using serialize::write; - write(buf, constraint.message); + write(buf, constraint.hashed_message); write(buf, constraint.signature); write(buf, constraint.pub_x_indices); write(buf, constraint.pub_y_indices); diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp index 0724b15f911..eae9b7dcd0a 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp @@ -14,6 +14,12 @@ size_t generate_ecdsa_constraint(acir_format::EcdsaSecp256k1Constraint& ecdsa_co { std::string message_string = "Instructions unclear, ask again later."; + // hash the message since the dsl ecdsa gadget uses the prehashed message + // NOTE: If the hash being used outputs more than 32 bytes, then big-field will panic + std::vector message_buffer; + std::copy(message_string.begin(), message_string.end(), std::back_inserter(message_buffer)); + auto hashed_message = sha256::sha256(message_buffer); + crypto::ecdsa::key_pair account; account.private_key = curve::fr::random_element(); account.public_key = curve::g1::one * account.private_key; @@ -29,9 +35,9 @@ size_t generate_ecdsa_constraint(acir_format::EcdsaSecp256k1Constraint& ecdsa_co std::vector pub_y_indices_in; std::vector signature_in; size_t offset = 1; - for (size_t i = 0; i < message_string.size(); ++i) { + for (size_t i = 0; i < hashed_message.size(); ++i) { message_in.emplace_back(i + offset); - const auto byte = static_cast(message_string[i]); + const auto byte = static_cast(hashed_message[i]); witness_values.emplace_back(byte); } offset += message_in.size(); @@ -63,7 +69,7 @@ size_t generate_ecdsa_constraint(acir_format::EcdsaSecp256k1Constraint& ecdsa_co witness_values.emplace_back(1); ecdsa_constraint = acir_format::EcdsaSecp256k1Constraint{ - .message = message_in, + .hashed_message = message_in, .pub_x_indices = pub_x_indices_in, .pub_y_indices = pub_y_indices_in, .result = result_in, diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp index 59b97b6bbee..20d1c32aba3 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp @@ -24,6 +24,10 @@ template verify_signature_noassert(const stdlib::byte_array& message, const G1& public_key, const signature& sig); +template +bool_t verify_signature_prehashed_message_noassert(const stdlib::byte_array& hashed_message, + const G1& public_key, + const signature& sig); template static signature from_witness(Composer* ctx, const crypto::ecdsa::signature& input) diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp index 76eab940c19..a28b7817a3d 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp @@ -117,20 +117,17 @@ bool_t verify_signature(const stdlib::byte_array& message, * @tparam Fq * @tparam Fr * @tparam G1 - * @param message + * @param hashed_message * @param public_key * @param sig * @return bool_t */ template -bool_t verify_signature_noassert(const stdlib::byte_array& message, - const G1& public_key, - const signature& sig) +bool_t verify_signature_prehashed_message_noassert(const stdlib::byte_array& hashed_message, + const G1& public_key, + const signature& sig) { - Composer* ctx = message.get_context() ? message.get_context() : public_key.x.context; - - stdlib::byte_array hashed_message = - static_cast>(stdlib::sha256(message)); + Composer* ctx = hashed_message.get_context() ? hashed_message.get_context() : public_key.x.context; Fr z(hashed_message); z.assert_is_in_field(); @@ -186,6 +183,30 @@ bool_t verify_signature_noassert(const stdlib::byte_array& m return output; } +/** + * @brief Verify ECDSA signature. Returns 0 if signature fails (i.e. does not produce unsatisfiable constraints) + * + * @tparam Composer + * @tparam Curve + * @tparam Fq + * @tparam Fr + * @tparam G1 + * @param message + * @param public_key + * @param sig + * @return bool_t + */ +template +bool_t verify_signature_noassert(const stdlib::byte_array& message, + const G1& public_key, + const signature& sig) +{ + stdlib::byte_array hashed_message = + static_cast>(stdlib::sha256(message)); + + return verify_signature_prehashed_message_noassert(hashed_message, public_key, sig); +} + } // namespace ecdsa } // namespace stdlib } // namespace proof_system::plonk \ No newline at end of file