From cf6e1549af2b3b5c04f59cac6a3d3ab5b0594c5c Mon Sep 17 00:00:00 2001 From: kevaundray Date: Thu, 11 May 2023 22:05:19 +0100 Subject: [PATCH] DSL: Add valid dummy data for ecdsa constraints when verifier is creating circuit (https://github.com/AztecProtocol/barretenberg/pull/438) * Add way to make verifiers data valid by replacing zeroes with valid public keys and signatures Co-authored-by: Zachary James Williamson * Update cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp * replace templates with concrete methods * add comment * PR review * add comments * change to use boolean flag, so dummy_ecdsa method lives in ecdsa * ad true as default --------- Co-authored-by: Zachary James Williamson --- .../dsl/acir_format/acir_format.cpp | 5 +- .../dsl/acir_format/ecdsa_secp256k1.cpp | 58 ++++++++++++++++++- .../dsl/acir_format/ecdsa_secp256k1.hpp | 6 +- .../dsl/acir_format/ecdsa_secp256k1.test.cpp | 28 +++++++++ 4 files changed, 92 insertions(+), 5 deletions(-) diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index a8c707943c3..0e2e510f4dc 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -23,7 +23,6 @@ void create_circuit(Composer& composer, const acir_format& constraint_system) if (std::find(constraint_system.public_inputs.begin(), constraint_system.public_inputs.end(), i) != constraint_system.public_inputs.end()) { composer.add_public_variable(0); - } else { composer.add_variable(0); } @@ -62,7 +61,7 @@ void create_circuit(Composer& composer, const acir_format& constraint_system) // Add ECDSA constraints for (const auto& constraint : constraint_system.ecdsa_constraints) { - create_ecdsa_verify_constraints(composer, constraint); + create_ecdsa_verify_constraints(composer, constraint, false); } // Add blake2s constraints @@ -145,7 +144,7 @@ Composer create_circuit(const acir_format& constraint_system, // Add ECDSA constraints for (const auto& constraint : constraint_system.ecdsa_constraints) { - create_ecdsa_verify_constraints(composer, constraint); + create_ecdsa_verify_constraints(composer, constraint, false); } // Add blake2s constraints 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 5a9caaa6997..31cddb3e2f6 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 @@ -84,9 +84,15 @@ witness_ct ecdsa_index_to_witness(Composer& composer, uint32_t index) return { &composer, value }; } -void create_ecdsa_verify_constraints(Composer& composer, const EcdsaSecp256k1Constraint& input) +void create_ecdsa_verify_constraints(Composer& composer, + const EcdsaSecp256k1Constraint& input, + bool has_valid_witness_assignments) { + if (has_valid_witness_assignments == false) { + dummy_ecdsa_constraint(composer, input); + } + auto new_sig = ecdsa_convert_signature(composer, input.signature); auto message = ecdsa_vector_of_bytes_to_byte_array(composer, input.hashed_message); @@ -127,4 +133,54 @@ void create_ecdsa_verify_constraints(Composer& composer, const EcdsaSecp256k1Con composer.assert_equal(signature_result_normalized.witness_index, input.result); } +// Add dummy constraints for ECDSA because when the verifier creates the +// constraint system, they usually use zeroes for witness values. +// +// This does not work for ECDSA as the signature, r, s and public key need +// to be valid. +void dummy_ecdsa_constraint(Composer& composer, EcdsaSecp256k1Constraint const& input) +{ + + std::vector pub_x_indices_; + std::vector pub_y_indices_; + std::vector signature_; + signature_.resize(64); + + // Create a valid signature with a valid public key + crypto::ecdsa::key_pair account; + account.private_key = 10; + account.public_key = secp256k1_ct::g1::one * account.private_key; + uint256_t pub_x_value = account.public_key.x; + uint256_t pub_y_value = account.public_key.y; + std::string message_string = "Instructions unclear, ask again later."; + crypto::ecdsa::signature signature = + crypto::ecdsa::construct_signature( + message_string, account); + + // Create new variables which will reference the valid public key and signature. + // We don't use them in a gate, so when we call assert_equal, they will be + // replaced as if they never existed. + for (size_t i = 0; i < 32; ++i) { + uint32_t x_wit = composer.add_variable(pub_x_value.slice(248 - i * 8, 256 - i * 8)); + uint32_t y_wit = composer.add_variable(pub_y_value.slice(248 - i * 8, 256 - i * 8)); + uint32_t r_wit = composer.add_variable(signature.r[i]); + uint32_t s_wit = composer.add_variable(signature.s[i]); + pub_x_indices_.emplace_back(x_wit); + pub_y_indices_.emplace_back(y_wit); + signature_[i] = r_wit; + signature_[i + 32] = s_wit; + } + + // Call assert_equal(from, to) to replace the value in `to` by the value in `from` + for (size_t i = 0; i < input.pub_x_indices.size(); ++i) { + composer.assert_equal(pub_x_indices_[i], input.pub_x_indices[i]); + } + for (size_t i = 0; i < input.pub_y_indices.size(); ++i) { + composer.assert_equal(pub_y_indices_[i], input.pub_y_indices[i]); + } + for (size_t i = 0; i < input.signature.size(); ++i) { + composer.assert_equal(signature_[i], input.signature[i]); + } +} + } // namespace acir_format 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 93a87d386c6..59d1fe48e02 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 @@ -26,7 +26,11 @@ struct EcdsaSecp256k1Constraint { friend bool operator==(EcdsaSecp256k1Constraint const& lhs, EcdsaSecp256k1Constraint const& rhs) = default; }; -void create_ecdsa_verify_constraints(Composer& composer, const EcdsaSecp256k1Constraint& input); +void create_ecdsa_verify_constraints(Composer& composer, + const EcdsaSecp256k1Constraint& input, + bool has_valid_witness_assignments = true); + +void dummy_ecdsa_constraint(Composer& composer, EcdsaSecp256k1Constraint const& input); template inline void read(B& buf, EcdsaSecp256k1Constraint& constraint) { 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 eae9b7dcd0a..4e2e25174a9 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 @@ -110,6 +110,34 @@ TEST(ECDSASecp256k1, TestECDSAConstraintSucceed) EXPECT_EQ(verifier.verify_proof(proof), true); } +// Test that the verifier can create an ECDSA circuit. +// The ECDSA circuit requires that certain dummy data is valid +// even though we are just building the circuit. +TEST(ECDSASecp256k1, TestECDSACompilesForVerifier) +{ + acir_format::EcdsaSecp256k1Constraint ecdsa_constraint; + std::vector witness_values; + size_t num_variables = generate_ecdsa_constraint(ecdsa_constraint, witness_values); + acir_format::acir_format constraint_system{ + .varnum = static_cast(num_variables), + .public_inputs = {}, + .fixed_base_scalar_mul_constraints = {}, + .logic_constraints = {}, + .range_constraints = {}, + .schnorr_constraints = {}, + .ecdsa_constraints = { ecdsa_constraint }, + .sha256_constraints = {}, + .blake2s_constraints = {}, + .keccak_constraints = {}, + .hash_to_field_constraints = {}, + .pedersen_constraints = {}, + .compute_merkle_root_constraints = {}, + .constraints = {}, + }; + auto crs_factory = std::make_unique(); + auto composer = create_circuit(constraint_system, std::move(crs_factory)); +} + TEST(ECDSASecp256k1, TestECDSAConstraintFail) { acir_format::EcdsaSecp256k1Constraint ecdsa_constraint;