diff --git a/cpp/bin-test/target/main.json b/cpp/bin-test/target/main.json index e75bd0d9aa..3883d10a30 100644 --- a/cpp/bin-test/target/main.json +++ b/cpp/bin-test/target/main.json @@ -1 +1 @@ -{"backend":"dummy-backend-bb.js","abi":{"parameters":[{"name":"verification_key","type":{"kind":"array","length":114,"type":{"kind":"field"}},"visibility":"private"},{"name":"proof","type":{"kind":"array","length":94,"type":{"kind":"field"}},"visibility":"private"},{"name":"public_inputs","type":{"kind":"array","length":1,"type":{"kind":"field"}},"visibility":"private"},{"name":"key_hash","type":{"kind":"field"},"visibility":"private"},{"name":"input_aggregation_object","type":{"kind":"array","length":16,"type":{"kind":"field"}},"visibility":"private"},{"name":"proof_b","type":{"kind":"array","length":94,"type":{"kind":"field"}},"visibility":"private"}],"param_witnesses":{"input_aggregation_object":[211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226],"key_hash":[210],"proof":[115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208],"proof_b":[227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320],"public_inputs":[209],"verification_key":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114]},"return_type":{"kind":"array","length":16,"type":{"kind":"field"}},"return_witnesses":[337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352]},"bytecode":"H4sIAAAAAAAA/+3WQ7PcWQDG4fOObTNj287YMxl7JmPbtm3Htm1bXyG2zefWzSaLLFK3KotUTtXT1auurnp//9NdSh4ppexWSm7hVm7jdu7gTu7ibu7hXu7jfh7gQR6iZtmwswWvkLXvt2QrtmYbtmU7tmcHdmQndmYXdq38zmV39mBP9mJv9mFf9mN/DuBADuJgDuFQqnEYh3MER3IUR3MMx3Icx3MCJ3ISJ3MKp3Iap3MGZ3IWZ3MO53Ie53MBF3IRF3MJ1bmUy7icK7iSq7iaa7iW67ieG7iRm7iZGtis2KzYrNis2KzYrNis2KzYrNis2KzYrNis2KzYrNTkYSr2f5THeJwneJKneJpneJbneJ4XeJGXeHntjhWf+Sqv8Tpv8CZv8Tbv8C7v8T4f8CEf8TGf8Cmf8Tlf8CVf8TXf8C3f8T0/8CM/8TO/8Cu/8Tt/8Cd/8Tf/8C//8T+1qE0d6lKP+jSgIY1oTBOa0ozmtKAlrWhNG9rSjvZ0oCOd6EwXutKN7vSgJ73oTR/60o/+DGAggxjMEIYyjOGMYCSjGM2YUvkMjWVcqfKJHqPH6DF6jB6jx+gxeoweo8foMXqMHqPH6DE1StXP5jth07oTxjOBiUxiMlOYyjSmM4OZzGI2c5jLPOazgIUsYjFLWMoylrOClaxidWU+8RINRUPRUDQUDUVD0VA0FA1FQ9FQNBQNRUOp+C3UUDQUDUVD0VA0FA1FQ9FQNBQNRUPRUDQUDaUaGoqGoqFoKBqKhqKhaCgaioaioWgoGoqGoqFoKBqKhqKhaCgaioaioWgoGoqGoqFoKBqKhqKhVC/r3AlVfaY36v+C9Z41mprLcKgIAAA=","proving_key":[],"verification_key":[],"gates":505501} \ No newline at end of file +{"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"verification_key","type":{"kind":"array","length":114,"type":{"kind":"field"}},"visibility":"private"},{"name":"proof","type":{"kind":"array","length":94,"type":{"kind":"field"}},"visibility":"private"},{"name":"public_inputs","type":{"kind":"array","length":1,"type":{"kind":"field"}},"visibility":"private"},{"name":"key_hash","type":{"kind":"field"},"visibility":"private"},{"name":"input_aggregation_object","type":{"kind":"array","length":16,"type":{"kind":"field"}},"visibility":"private"},{"name":"proof_b","type":{"kind":"array","length":94,"type":{"kind":"field"}},"visibility":"private"}],"param_witnesses":{"input_aggregation_object":[211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226],"key_hash":[210],"proof":[115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208],"proof_b":[227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320],"public_inputs":[209],"verification_key":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114]},"return_type":{"kind":"array","length":16,"type":{"kind":"field"}},"return_witnesses":[337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352]},"bytecode":"H4sIAAAAAAAA/+3WU6/dWQDG4fWObbNj2+7YMx17pmPbtm3Xtm1bX6G2zefk9KZJb5qT9KLpSp6dfbWzk/f3X3uXkkdKKbuVklu4ldu4nTu4k7u4m3u4l/u4nwd4kIeoWTb8bMErZO37LdmKrdmGbdmO7dmBHdmJndmFXSu/d9mdPdiTvdibfdiX/difAziQgziYQziUahzG4RzBkRzF0RzDsRzH8ZzAiZzEyZzCqZzG6ZzBmZzF2ZzDuZzH+VzAhVzExVxCdS7lMi7nCq7kKq7mGq7lOq7nBm7kJm6mBnYrdit2K3Yrdit2K3Yrdit2K3Yrdit2K3Yrdit2KzV5mIoGHuUxHucJnuQpnuYZnuU5nucFXuQlXl67Y8VnvsprvM4bvMlbvM07vMt7vM8HfMhHfMwnfMpnfM4XfMlXfM03fMt3fM8P/MhP/Mwv/Mpv/M4f/Mlf/M0//Mt//E8talOHutSjPg1oSCMa04SmNKM5LWhJK1rThra0oz0d6EgnOtOFrnSjOz3oSS9604e+9KM/AxjIIAYzhKEMYzgjGMkoRjOmVD5DYxlXqnyix+gxeoweo8foMXqMHqPH6DF6jB6jx+gxekyNUvWz+U7YtO6E8UxgIpOYzBSmMo3pzGAms5jNHOYyj/ksYCGLWMwSlrKM5axgJatYXZlPvERD0VA0FA1FQ9FQNBQNRUPRUDQUDUVD0VAqfg81FA1FQ9FQNBQNRUPRUDQUDUVD0VA0FA1FQ6mGhqKhaCgaioaioWgoGoqGoqFoKBqKhqKhaCgaioaioWgoGoqGoqFoKBqKhqKhaCgaioaioWgo1cs6d0JVn+mN/t9gvWcN6fQg96wIAAA=","proving_key":[],"verification_key":[]} \ No newline at end of file diff --git a/cpp/src/barretenberg/crypto/ecdsa/ecdsa.hpp b/cpp/src/barretenberg/crypto/ecdsa/ecdsa.hpp index 4089835ea6..8275da011e 100644 --- a/cpp/src/barretenberg/crypto/ecdsa/ecdsa.hpp +++ b/cpp/src/barretenberg/crypto/ecdsa/ecdsa.hpp @@ -1,6 +1,9 @@ #pragma once #include "../hashers/hashers.hpp" #include "barretenberg/ecc/curves/secp256k1/secp256k1.hpp" + +#include "barretenberg/ecc/curves/secp256r1/secp256r1.hpp" + #include "barretenberg/serialize/msgpack.hpp" #include #include @@ -70,6 +73,18 @@ template inline void write(B& buf, key_pair inline void read(B& it, key_pair& keypair) +{ + read(it, keypair.private_key); + read(it, keypair.public_key); +} + +template inline void write(B& buf, key_pair const& keypair) +{ + write(buf, keypair.private_key); + write(buf, keypair.public_key); +} + } // namespace ecdsa } // namespace crypto diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 0f136e572a..250efe82ec 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -54,9 +54,14 @@ void create_circuit(Builder& builder, acir_format const& constraint_system) create_schnorr_verify_constraints(builder, constraint); } - // Add ECDSA constraints - for (const auto& constraint : constraint_system.ecdsa_constraints) { - create_ecdsa_verify_constraints(builder, constraint, false); + // Add ECDSA K1 constraints + for (const auto& constraint : constraint_system.ecdsa_k1_constraints) { + create_ecdsa_k1_verify_constraints(builder, constraint, false); + } + + // Add ECDSA R1 constraints + for (const auto& constraint : constraint_system.ecdsa_r1_constraints) { + create_ecdsa_r1_verify_constraints(builder, constraint, false); } // Add blake2s constraints @@ -171,9 +176,14 @@ void create_circuit_with_witness(Builder& builder, acir_format const& constraint create_schnorr_verify_constraints(builder, constraint); } - // Add ECDSA constraints - for (const auto& constraint : constraint_system.ecdsa_constraints) { - create_ecdsa_verify_constraints(builder, constraint); + // Add ECDSA k1 constraints + for (const auto& constraint : constraint_system.ecdsa_k1_constraints) { + create_ecdsa_k1_verify_constraints(builder, constraint); + } + + // Add ECDSA r1 constraints + for (const auto& constraint : constraint_system.ecdsa_r1_constraints) { + create_ecdsa_r1_verify_constraints(builder, constraint); } // Add blake2s constraints diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp b/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp index c8293be96f..52572251b3 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp @@ -4,6 +4,7 @@ #include "blake2s_constraint.hpp" #include "block_constraint.hpp" #include "ecdsa_secp256k1.hpp" +#include "ecdsa_secp256r1.hpp" #include "fixed_base_scalar_mul.hpp" #include "hash_to_field.hpp" #include "keccak_constraint.hpp" @@ -26,7 +27,8 @@ struct acir_format { std::vector logic_constraints; std::vector range_constraints; std::vector schnorr_constraints; - std::vector ecdsa_constraints; + std::vector ecdsa_k1_constraints; + std::vector ecdsa_r1_constraints; std::vector sha256_constraints; std::vector blake2s_constraints; std::vector keccak_constraints; @@ -67,7 +69,8 @@ template inline void read(B& buf, acir_format& data) read(buf, data.range_constraints); read(buf, data.sha256_constraints); read(buf, data.schnorr_constraints); - read(buf, data.ecdsa_constraints); + read(buf, data.ecdsa_k1_constraints); + read(buf, data.ecdsa_r1_constraints); read(buf, data.blake2s_constraints); read(buf, data.keccak_constraints); read(buf, data.keccak_var_constraints); @@ -88,7 +91,8 @@ template inline void write(B& buf, acir_format const& data) write(buf, data.range_constraints); write(buf, data.sha256_constraints); write(buf, data.schnorr_constraints); - write(buf, data.ecdsa_constraints); + write(buf, data.ecdsa_k1_constraints); + write(buf, data.ecdsa_r1_constraints); write(buf, data.blake2s_constraints); write(buf, data.keccak_constraints); write(buf, data.keccak_var_constraints); diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp b/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp index 101870479d..8abaee1610 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp @@ -29,7 +29,8 @@ TEST(acir_format, test_a_single_constraint_no_pub_inputs) .logic_constraints = {}, .range_constraints = {}, .schnorr_constraints = {}, - .ecdsa_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, @@ -135,7 +136,8 @@ TEST(acir_format, test_logic_gate_from_noir_circuit) .logic_constraints = { logic_constraint }, .range_constraints = { range_a, range_b }, .schnorr_constraints = {}, - .ecdsa_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, @@ -201,7 +203,8 @@ TEST(acir_format, test_schnorr_verify_pass) .logic_constraints = {}, .range_constraints = range_constraints, .schnorr_constraints = { schnorr_constraint }, - .ecdsa_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, @@ -274,7 +277,8 @@ TEST(acir_format, test_schnorr_verify_small_range) .logic_constraints = {}, .range_constraints = range_constraints, .schnorr_constraints = { schnorr_constraint }, - .ecdsa_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, diff --git a/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp b/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp index f813634c44..89a47f0f72 100644 --- a/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp @@ -110,7 +110,8 @@ TEST(up_ram, TestBlockConstraint) .logic_constraints = {}, .range_constraints = {}, .schnorr_constraints = {}, - .ecdsa_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, diff --git a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp index 0bfe09ada2..6cebc71c54 100644 --- a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp @@ -1,5 +1,4 @@ #include "ecdsa_secp256k1.hpp" -#include "barretenberg/crypto/ecdsa/ecdsa.hpp" #include "barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp" namespace acir_format { @@ -84,9 +83,9 @@ witness_ct ecdsa_index_to_witness(Builder& builder, uint32_t index) return { &builder, value }; } -void create_ecdsa_verify_constraints(Builder& builder, - const EcdsaSecp256k1Constraint& input, - bool has_valid_witness_assignments) +void create_ecdsa_k1_verify_constraints(Builder& builder, + const EcdsaSecp256k1Constraint& input, + bool has_valid_witness_assignments) { if (has_valid_witness_assignments == false) { @@ -144,6 +143,7 @@ void dummy_ecdsa_constraint(Builder& builder, EcdsaSecp256k1Constraint const& in std::vector pub_x_indices_; std::vector pub_y_indices_; std::vector signature_; + std::vector message_indices_; signature_.resize(64); // Create a valid signature with a valid public key @@ -161,10 +161,12 @@ void dummy_ecdsa_constraint(Builder& builder, EcdsaSecp256k1Constraint const& in // 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 m_wit = builder.add_variable(input.hashed_message[i]); uint32_t x_wit = builder.add_variable(pub_x_value.slice(248 - i * 8, 256 - i * 8)); uint32_t y_wit = builder.add_variable(pub_y_value.slice(248 - i * 8, 256 - i * 8)); uint32_t r_wit = builder.add_variable(signature.r[i]); uint32_t s_wit = builder.add_variable(signature.s[i]); + message_indices_.emplace_back(m_wit); pub_x_indices_.emplace_back(x_wit); pub_y_indices_.emplace_back(y_wit); signature_[i] = r_wit; @@ -172,6 +174,9 @@ void dummy_ecdsa_constraint(Builder& builder, EcdsaSecp256k1Constraint const& in } // Call assert_equal(from, to) to replace the value in `to` by the value in `from` + for (size_t i = 0; i < input.hashed_message.size(); ++i) { + builder.assert_equal(message_indices_[i], input.hashed_message[i]); + } for (size_t i = 0; i < input.pub_x_indices.size(); ++i) { builder.assert_equal(pub_x_indices_[i], input.pub_x_indices[i]); } diff --git a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp index 05400e09f5..a1cc8d81e3 100644 --- a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp +++ b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp @@ -1,4 +1,5 @@ #pragma once +#include "barretenberg/crypto/ecdsa/ecdsa.hpp" #include "barretenberg/dsl/types.hpp" #include @@ -26,12 +27,16 @@ struct EcdsaSecp256k1Constraint { friend bool operator==(EcdsaSecp256k1Constraint const& lhs, EcdsaSecp256k1Constraint const& rhs) = default; }; -void create_ecdsa_verify_constraints(Builder& builder, - const EcdsaSecp256k1Constraint& input, - bool has_valid_witness_assignments = true); +void create_ecdsa_k1_verify_constraints(Builder& builder, + const EcdsaSecp256k1Constraint& input, + bool has_valid_witness_assignments = true); void dummy_ecdsa_constraint(Builder& builder, EcdsaSecp256k1Constraint const& input); +crypto::ecdsa::signature ecdsa_convert_signature(Builder& builder, std::vector signature); +witness_ct ecdsa_index_to_witness(Builder& builder, uint32_t index); +byte_array_ct ecdsa_vector_of_bytes_to_byte_array(Builder& builder, std::vector vector_of_bytes); + template inline void read(B& buf, EcdsaSecp256k1Constraint& constraint) { using serialize::read; diff --git a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp index 65a2c3e0e5..f216fd7ae8 100644 --- a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp @@ -81,9 +81,9 @@ size_t generate_ecdsa_constraint(EcdsaSecp256k1Constraint& ecdsa_constraint, Wit TEST(ECDSASecp256k1, TestECDSAConstraintSucceed) { - EcdsaSecp256k1Constraint ecdsa_constraint; + EcdsaSecp256k1Constraint ecdsa_k1_constraint; WitnessVector witness_values; - size_t num_variables = generate_ecdsa_constraint(ecdsa_constraint, witness_values); + size_t num_variables = generate_ecdsa_constraint(ecdsa_k1_constraint, witness_values); acir_format constraint_system{ .varnum = static_cast(num_variables), .public_inputs = {}, @@ -91,7 +91,8 @@ TEST(ECDSASecp256k1, TestECDSAConstraintSucceed) .logic_constraints = {}, .range_constraints = {}, .schnorr_constraints = {}, - .ecdsa_constraints = { ecdsa_constraint }, + .ecdsa_k1_constraints = { ecdsa_k1_constraint }, + .ecdsa_r1_constraints = {}, .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, @@ -105,7 +106,7 @@ TEST(ECDSASecp256k1, TestECDSAConstraintSucceed) auto builder = create_circuit_with_witness(constraint_system, witness_values); - EXPECT_EQ(builder.get_variable(ecdsa_constraint.result), 1); + EXPECT_EQ(builder.get_variable(ecdsa_k1_constraint.result), 1); auto composer = Composer(); auto prover = composer.create_prover(builder); @@ -120,9 +121,9 @@ TEST(ECDSASecp256k1, TestECDSAConstraintSucceed) // even though we are just building the circuit. TEST(ECDSASecp256k1, TestECDSACompilesForVerifier) { - EcdsaSecp256k1Constraint ecdsa_constraint; + EcdsaSecp256k1Constraint ecdsa_k1_constraint; WitnessVector witness_values; - size_t num_variables = generate_ecdsa_constraint(ecdsa_constraint, witness_values); + size_t num_variables = generate_ecdsa_constraint(ecdsa_k1_constraint, witness_values); acir_format constraint_system{ .varnum = static_cast(num_variables), .public_inputs = {}, @@ -130,7 +131,8 @@ TEST(ECDSASecp256k1, TestECDSACompilesForVerifier) .logic_constraints = {}, .range_constraints = {}, .schnorr_constraints = {}, - .ecdsa_constraints = { ecdsa_constraint }, + .ecdsa_k1_constraints = { ecdsa_k1_constraint }, + .ecdsa_r1_constraints = {}, .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, @@ -146,9 +148,9 @@ TEST(ECDSASecp256k1, TestECDSACompilesForVerifier) TEST(ECDSASecp256k1, TestECDSAConstraintFail) { - EcdsaSecp256k1Constraint ecdsa_constraint; + EcdsaSecp256k1Constraint ecdsa_k1_constraint; WitnessVector witness_values; - size_t num_variables = generate_ecdsa_constraint(ecdsa_constraint, witness_values); + size_t num_variables = generate_ecdsa_constraint(ecdsa_k1_constraint, witness_values); // set result value to be false witness_values[witness_values.size() - 1] = 0; @@ -163,7 +165,8 @@ TEST(ECDSASecp256k1, TestECDSAConstraintFail) .logic_constraints = {}, .range_constraints = {}, .schnorr_constraints = {}, - .ecdsa_constraints = { ecdsa_constraint }, + .ecdsa_k1_constraints = { ecdsa_k1_constraint }, + .ecdsa_r1_constraints = {}, .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, @@ -176,7 +179,7 @@ TEST(ECDSASecp256k1, TestECDSAConstraintFail) }; auto builder = create_circuit_with_witness(constraint_system, witness_values); - EXPECT_EQ(builder.get_variable(ecdsa_constraint.result), 0); + EXPECT_EQ(builder.get_variable(ecdsa_k1_constraint.result), 0); auto composer = Composer(); auto prover = composer.create_prover(builder); diff --git a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.cpp b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.cpp new file mode 100644 index 0000000000..7d1feeecbf --- /dev/null +++ b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.cpp @@ -0,0 +1,140 @@ +#include "ecdsa_secp256r1.hpp" +#include "barretenberg/crypto/ecdsa/ecdsa.hpp" +#include "barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp" +#include "ecdsa_secp256k1.hpp" + +namespace acir_format { + +using namespace proof_system::plonk; + +secp256r1_ct::g1_ct ecdsa_convert_inputs(Builder* ctx, const secp256r1::g1::affine_element& input) +{ + uint256_t x_u256(input.x); + uint256_t y_u256(input.y); + secp256r1_ct::fq_ct x(witness_ct(ctx, barretenberg::fr(x_u256.slice(0, secp256r1_ct::fq_ct::NUM_LIMB_BITS * 2))), + witness_ct(ctx, + barretenberg::fr(x_u256.slice(secp256r1_ct::fq_ct::NUM_LIMB_BITS * 2, + secp256r1_ct::fq_ct::NUM_LIMB_BITS * 4)))); + secp256r1_ct::fq_ct y(witness_ct(ctx, barretenberg::fr(y_u256.slice(0, secp256r1_ct::fq_ct::NUM_LIMB_BITS * 2))), + witness_ct(ctx, + barretenberg::fr(y_u256.slice(secp256r1_ct::fq_ct::NUM_LIMB_BITS * 2, + secp256r1_ct::fq_ct::NUM_LIMB_BITS * 4)))); + + return { x, y }; +} + +void create_ecdsa_r1_verify_constraints(Builder& builder, + const EcdsaSecp256r1Constraint& input, + bool has_valid_witness_assignments) +{ + + if (has_valid_witness_assignments == false) { + dummy_ecdsa_constraint(builder, input); + } + + auto new_sig = ecdsa_convert_signature(builder, input.signature); + + auto message = ecdsa_vector_of_bytes_to_byte_array(builder, input.hashed_message); + auto pub_key_x_byte_arr = ecdsa_vector_of_bytes_to_byte_array(builder, input.pub_x_indices); + auto pub_key_y_byte_arr = ecdsa_vector_of_bytes_to_byte_array(builder, input.pub_y_indices); + + auto pub_key_x_fq = secp256r1_ct::fq_ct(pub_key_x_byte_arr); + auto pub_key_y_fq = secp256r1_ct::fq_ct(pub_key_y_byte_arr); + + std::vector rr(new_sig.r.begin(), new_sig.r.end()); + std::vector ss(new_sig.s.begin(), new_sig.s.end()); + uint8_t vv = new_sig.v; + + stdlib::ecdsa::signature sig{ stdlib::byte_array(&builder, rr), + stdlib::byte_array(&builder, ss), + stdlib::uint8(&builder, vv) }; + + pub_key_x_fq.assert_is_in_field(); + pub_key_y_fq.assert_is_in_field(); + secp256r1_ct::g1_bigfr_ct public_key = secp256r1_ct::g1_bigfr_ct(pub_key_x_fq, pub_key_y_fq); + for (size_t i = 0; i < 32; ++i) { + sig.r[i].assert_equal(field_ct::from_witness_index(&builder, input.signature[i])); + sig.s[i].assert_equal(field_ct::from_witness_index(&builder, input.signature[i + 32])); + pub_key_x_byte_arr[i].assert_equal(field_ct::from_witness_index(&builder, input.pub_x_indices[i])); + pub_key_y_byte_arr[i].assert_equal(field_ct::from_witness_index(&builder, input.pub_y_indices[i])); + } + for (size_t i = 0; i < input.hashed_message.size(); ++i) { + message[i].assert_equal(field_ct::from_witness_index(&builder, input.hashed_message[i])); + } + + bool_ct signature_result = + stdlib::ecdsa::verify_signature_prehashed_message_noassert(message, public_key, sig); + bool_ct signature_result_normalized = signature_result.normalize(); + builder.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(Builder& builder, EcdsaSecp256r1Constraint const& input) +{ + + std::vector pub_x_indices_; + std::vector pub_y_indices_; + std::vector signature_; + std::vector message_indices_; + signature_.resize(64); + + // Create a valid signature with a valid public key + 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 = 10; + account.public_key = secp256r1::g1::one * account.private_key; + + crypto::ecdsa::signature signature = + crypto::ecdsa::construct_signature(message_string, + account); + + uint256_t pub_x_value = account.public_key.x; + uint256_t pub_y_value = account.public_key.y; + + // 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 m_wit = builder.add_variable(hashed_message[i]); + uint32_t x_wit = builder.add_variable(pub_x_value.slice(248 - i * 8, 256 - i * 8)); + uint32_t y_wit = builder.add_variable(pub_y_value.slice(248 - i * 8, 256 - i * 8)); + uint32_t r_wit = builder.add_variable(signature.r[i]); + uint32_t s_wit = builder.add_variable(signature.s[i]); + message_indices_.emplace_back(m_wit); + 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.hashed_message.size(); ++i) { + builder.assert_equal(message_indices_[i], input.hashed_message[i]); + } + for (size_t i = 0; i < input.pub_x_indices.size(); ++i) { + builder.assert_equal(pub_x_indices_[i], input.pub_x_indices[i]); + } + for (size_t i = 0; i < input.pub_y_indices.size(); ++i) { + builder.assert_equal(pub_y_indices_[i], input.pub_y_indices[i]); + } + for (size_t i = 0; i < input.signature.size(); ++i) { + builder.assert_equal(signature_[i], input.signature[i]); + } +} + +} // namespace acir_format diff --git a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.hpp b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.hpp new file mode 100644 index 0000000000..a47cab2ea4 --- /dev/null +++ b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.hpp @@ -0,0 +1,55 @@ +#pragma once +#include "barretenberg/dsl/types.hpp" +#include + +namespace acir_format { + +struct EcdsaSecp256r1Constraint { + // 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. + // Since Fr does not have enough bits to represent + // the prime field in secp256r1, a byte array is used. + // Can also use low and hi where lo=128 bits + std::vector pub_x_indices; + std::vector pub_y_indices; + + // This is the result of verifying the signature + uint32_t result; + + // This is the computed signature + // + std::vector signature; + + friend bool operator==(EcdsaSecp256r1Constraint const& lhs, EcdsaSecp256r1Constraint const& rhs) = default; +}; + +void create_ecdsa_r1_verify_constraints(Builder& builder, + const EcdsaSecp256r1Constraint& input, + bool has_valid_witness_assignments = true); + +void dummy_ecdsa_constraint(Builder& builder, EcdsaSecp256r1Constraint const& input); + +template inline void read(B& buf, EcdsaSecp256r1Constraint& constraint) +{ + using serialize::read; + read(buf, constraint.hashed_message); + read(buf, constraint.signature); + read(buf, constraint.pub_x_indices); + read(buf, constraint.pub_y_indices); + read(buf, constraint.result); +} + +template inline void write(B& buf, EcdsaSecp256r1Constraint const& constraint) +{ + using serialize::write; + write(buf, constraint.hashed_message); + write(buf, constraint.signature); + write(buf, constraint.pub_x_indices); + write(buf, constraint.pub_y_indices); + write(buf, constraint.result); +} + +} // namespace acir_format diff --git a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp new file mode 100644 index 0000000000..68d85570cb --- /dev/null +++ b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp @@ -0,0 +1,267 @@ +#include "acir_format.hpp" +#include "barretenberg/crypto/ecdsa/ecdsa.hpp" +#include "barretenberg/plonk/proof_system/types/proof.hpp" +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" +#include "ecdsa_secp256r1.hpp" + +#include +#include + +namespace acir_format::tests { +using curve_ct = proof_system::plonk::stdlib::secp256r1; + +// Generate r1 constraints given pre generated pubkey, sig and message values +size_t generate_r1_constraints(EcdsaSecp256r1Constraint& ecdsa_r1_constraint, + WitnessVector& witness_values, + uint256_t pub_x_value, + uint256_t pub_y_value, + std::array hashed_message, + crypto::ecdsa::signature signature) +{ + + std::vector message_in; + std::vector pub_x_indices_in; + std::vector pub_y_indices_in; + std::vector signature_in; + size_t offset = 1; + for (size_t i = 0; i < hashed_message.size(); ++i) { + message_in.emplace_back(i + offset); + const auto byte = static_cast(hashed_message[i]); + witness_values.emplace_back(byte); + } + offset += message_in.size(); + + for (size_t i = 0; i < 32; ++i) { + pub_x_indices_in.emplace_back(i + offset); + witness_values.emplace_back(pub_x_value.slice(248 - i * 8, 256 - i * 8)); + } + offset += pub_x_indices_in.size(); + for (size_t i = 0; i < 32; ++i) { + pub_y_indices_in.emplace_back(i + offset); + witness_values.emplace_back(pub_y_value.slice(248 - i * 8, 256 - i * 8)); + } + offset += pub_y_indices_in.size(); + for (size_t i = 0; i < 32; ++i) { + signature_in.emplace_back(i + offset); + witness_values.emplace_back(signature.r[i]); + } + offset += signature.r.size(); + for (size_t i = 0; i < 32; ++i) { + signature_in.emplace_back(i + offset); + witness_values.emplace_back(signature.s[i]); + } + offset += signature.s.size(); + + witness_values.emplace_back(1); + const auto result_in = static_cast(offset); + offset += 1; + witness_values.emplace_back(1); + + ecdsa_r1_constraint = EcdsaSecp256r1Constraint{ + .hashed_message = message_in, + .pub_x_indices = pub_x_indices_in, + .pub_y_indices = pub_y_indices_in, + .result = result_in, + .signature = signature_in, + }; + return offset; +} + +size_t generate_ecdsa_constraint(EcdsaSecp256r1Constraint& ecdsa_r1_constraint, WitnessVector& witness_values) +{ + + 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_ct::fr::random_element(); + account.public_key = curve_ct::g1::one * account.private_key; + + crypto::ecdsa::signature signature = + crypto::ecdsa::construct_signature(message_string, + account); + + return generate_r1_constraints( + ecdsa_r1_constraint, witness_values, account.public_key.x, account.public_key.y, hashed_message, signature); +} + +TEST(ECDSASecp256r1, test_hardcoded) +{ + EcdsaSecp256r1Constraint ecdsa_r1_constraint; + WitnessVector witness_values; + + std::string message = "ECDSA proves knowledge of a secret number in the context of a single message"; + std::array hashed_message = { + 84, 112, 91, 163, 186, 175, 219, 223, 186, 140, 95, 154, 112, 247, 168, 155, + 238, 152, 217, 6, 181, 62, 49, 7, 77, 167, 186, 236, 220, 13, 169, 173, + }; + + uint256_t pub_key_x = uint256_t("550f471003f3df97c3df506ac797f6721fb1a1fb7b8f6f83d224498a65c88e24"); + uint256_t pub_key_y = uint256_t("136093d7012e509a73715cbd0b00a3cc0ff4b5c01b3ffa196ab1fb327036b8e6"); + + // 0x2c70a8d084b62bfc5ce03641caf9f72ad4da8c81bfe6ec9487bb5e1bef62a13218ad9ee29eaf351fdc50f1520c425e9b908a07278b43b0ec7b872778c14e0784 + crypto::ecdsa::signature signature = { + .r = { 44, 112, 168, 208, 132, 182, 43, 252, 92, 224, 54, 65, 202, 249, 247, 42, + 212, 218, 140, 129, 191, 230, 236, 148, 135, 187, 94, 27, 239, 98, 161, 50 }, + .s = { 24, 173, 158, 226, 158, 175, 53, 31, 220, 80, 241, 82, 12, 66, 94, 155, + 144, 138, 7, 39, 139, 67, 176, 236, 123, 135, 39, 120, 193, 78, 7, 132 }, + .v = 0 + }; + + crypto::ecdsa::key_pair account; + account.private_key = curve_ct::fr(uint256_t("020202020202020202020202020202020202020202020202020202020202020202")); + + account.public_key = curve_ct::g1::one * account.private_key; + + size_t num_variables = + generate_r1_constraints(ecdsa_r1_constraint, witness_values, pub_key_x, pub_key_y, hashed_message, signature); + acir_format constraint_system{ + .varnum = static_cast(num_variables), + .public_inputs = {}, + .fixed_base_scalar_mul_constraints = {}, + .logic_constraints = {}, + .range_constraints = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = { ecdsa_r1_constraint }, + .sha256_constraints = {}, + .blake2s_constraints = {}, + .keccak_constraints = {}, + .keccak_var_constraints = {}, + .hash_to_field_constraints = {}, + .pedersen_constraints = {}, + .block_constraints = {}, + .recursion_constraints = {}, + .constraints = {}, + }; + + secp256r1::g1::affine_element pub_key = { pub_key_x, pub_key_y }; + bool we_ballin = crypto::ecdsa::verify_signature( + message, pub_key, signature); + EXPECT_EQ(we_ballin, true); + + auto builder = create_circuit_with_witness(constraint_system, witness_values); + + EXPECT_EQ(builder.get_variable(ecdsa_r1_constraint.result), 1); + auto composer = Composer(); + auto prover = composer.create_prover(builder); + + auto proof = prover.construct_proof(); + auto verifier = composer.create_verifier(builder); + EXPECT_EQ(verifier.verify_proof(proof), true); +} + +TEST(ECDSASecp256r1, TestECDSAConstraintSucceed) +{ + EcdsaSecp256r1Constraint ecdsa_r1_constraint; + WitnessVector witness_values; + size_t num_variables = generate_ecdsa_constraint(ecdsa_r1_constraint, witness_values); + acir_format constraint_system{ + .varnum = static_cast(num_variables), + .public_inputs = {}, + .fixed_base_scalar_mul_constraints = {}, + .logic_constraints = {}, + .range_constraints = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = { ecdsa_r1_constraint }, + .sha256_constraints = {}, + .blake2s_constraints = {}, + .keccak_constraints = {}, + .keccak_var_constraints = {}, + .hash_to_field_constraints = {}, + .pedersen_constraints = {}, + .block_constraints = {}, + .recursion_constraints = {}, + .constraints = {}, + }; + + auto builder = create_circuit_with_witness(constraint_system, witness_values); + + EXPECT_EQ(builder.get_variable(ecdsa_r1_constraint.result), 1); + auto composer = Composer(); + auto prover = composer.create_prover(builder); + + auto proof = prover.construct_proof(); + auto verifier = composer.create_verifier(builder); + 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(ECDSASecp256r1, TestECDSACompilesForVerifier) +{ + EcdsaSecp256r1Constraint ecdsa_r1_constraint; + WitnessVector witness_values; + size_t num_variables = generate_ecdsa_constraint(ecdsa_r1_constraint, witness_values); + acir_format constraint_system{ + .varnum = static_cast(num_variables), + .public_inputs = {}, + .fixed_base_scalar_mul_constraints = {}, + .logic_constraints = {}, + .range_constraints = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = { ecdsa_r1_constraint }, + .sha256_constraints = {}, + .blake2s_constraints = {}, + .keccak_constraints = {}, + .keccak_var_constraints = {}, + .hash_to_field_constraints = {}, + .pedersen_constraints = {}, + .block_constraints = {}, + .recursion_constraints = {}, + .constraints = {}, + }; + auto builder = create_circuit(constraint_system); +} + +TEST(ECDSASecp256r1, TestECDSAConstraintFail) +{ + EcdsaSecp256r1Constraint ecdsa_r1_constraint; + WitnessVector witness_values; + size_t num_variables = generate_ecdsa_constraint(ecdsa_r1_constraint, witness_values); + + // set result value to be false + witness_values[witness_values.size() - 1] = 0; + + // tamper with signature + witness_values[witness_values.size() - 20] += 1; + + acir_format constraint_system{ + .varnum = static_cast(num_variables), + .public_inputs = {}, + .fixed_base_scalar_mul_constraints = {}, + .logic_constraints = {}, + .range_constraints = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = { ecdsa_r1_constraint }, + .sha256_constraints = {}, + .blake2s_constraints = {}, + .keccak_constraints = {}, + .keccak_var_constraints = {}, + .hash_to_field_constraints = {}, + .pedersen_constraints = {}, + .block_constraints = {}, + .recursion_constraints = {}, + .constraints = {}, + }; + + auto builder = create_circuit_with_witness(constraint_system, witness_values); + + EXPECT_EQ(builder.get_variable(ecdsa_r1_constraint.result), 0); + auto composer = Composer(); + auto prover = composer.create_prover(builder); + + auto proof = prover.construct_proof(); + auto verifier = composer.create_verifier(builder); + EXPECT_EQ(verifier.verify_proof(proof), true); +} +} // namespace acir_format::tests \ No newline at end of file diff --git a/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp b/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp index 7174486788..adb34ea630 100644 --- a/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp @@ -84,7 +84,8 @@ Builder create_inner_circuit() .logic_constraints = { logic_constraint }, .range_constraints = { range_a, range_b }, .schnorr_constraints = {}, - .ecdsa_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, @@ -211,7 +212,8 @@ Builder create_outer_circuit(std::vector& inner_circuits) .logic_constraints = {}, .range_constraints = {}, .schnorr_constraints = {}, - .ecdsa_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, .sha256_constraints = {}, .blake2s_constraints = {}, .keccak_constraints = {}, diff --git a/cpp/src/barretenberg/dsl/types.hpp b/cpp/src/barretenberg/dsl/types.hpp index f6a8a1b11f..af7902ea0e 100644 --- a/cpp/src/barretenberg/dsl/types.hpp +++ b/cpp/src/barretenberg/dsl/types.hpp @@ -15,6 +15,7 @@ #include "barretenberg/stdlib/primitives/byte_array/byte_array.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/primitives/curves/secp256k1.hpp" +#include "barretenberg/stdlib/primitives/curves/secp256r1.hpp" #include "barretenberg/stdlib/primitives/memory/ram_table.hpp" #include "barretenberg/stdlib/primitives/memory/rom_table.hpp" #include "barretenberg/stdlib/primitives/packed_byte_array/packed_byte_array.hpp" @@ -60,6 +61,7 @@ using pedersen_commitment = proof_system::plonk::stdlib::pedersen_commitment; using bn254 = proof_system::plonk::stdlib::bn254; using secp256k1_ct = proof_system::plonk::stdlib::secp256k1; +using secp256r1_ct = proof_system::plonk::stdlib::secp256r1; using hash_path_ct = proof_system::plonk::stdlib::merkle_tree::hash_path; diff --git a/ts/bin-test/target/main.json b/ts/bin-test/target/main.json index e75bd0d9aa..3883d10a30 100644 --- a/ts/bin-test/target/main.json +++ b/ts/bin-test/target/main.json @@ -1 +1 @@ -{"backend":"dummy-backend-bb.js","abi":{"parameters":[{"name":"verification_key","type":{"kind":"array","length":114,"type":{"kind":"field"}},"visibility":"private"},{"name":"proof","type":{"kind":"array","length":94,"type":{"kind":"field"}},"visibility":"private"},{"name":"public_inputs","type":{"kind":"array","length":1,"type":{"kind":"field"}},"visibility":"private"},{"name":"key_hash","type":{"kind":"field"},"visibility":"private"},{"name":"input_aggregation_object","type":{"kind":"array","length":16,"type":{"kind":"field"}},"visibility":"private"},{"name":"proof_b","type":{"kind":"array","length":94,"type":{"kind":"field"}},"visibility":"private"}],"param_witnesses":{"input_aggregation_object":[211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226],"key_hash":[210],"proof":[115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208],"proof_b":[227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320],"public_inputs":[209],"verification_key":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114]},"return_type":{"kind":"array","length":16,"type":{"kind":"field"}},"return_witnesses":[337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352]},"bytecode":"H4sIAAAAAAAA/+3WQ7PcWQDG4fOObTNj287YMxl7JmPbtm3Htm1bXyG2zefWzSaLLFK3KotUTtXT1auurnp//9NdSh4ppexWSm7hVm7jdu7gTu7ibu7hXu7jfh7gQR6iZtmwswWvkLXvt2QrtmYbtmU7tmcHdmQndmYXdq38zmV39mBP9mJv9mFf9mN/DuBADuJgDuFQqnEYh3MER3IUR3MMx3Icx3MCJ3ISJ3MKp3Iap3MGZ3IWZ3MO53Ie53MBF3IRF3MJ1bmUy7icK7iSq7iaa7iW67ieG7iRm7iZGtis2KzYrNis2KzYrNis2KzYrNis2KzYrNis2KzYrNTkYSr2f5THeJwneJKneJpneJbneJ4XeJGXeHntjhWf+Sqv8Tpv8CZv8Tbv8C7v8T4f8CEf8TGf8Cmf8Tlf8CVf8TXf8C3f8T0/8CM/8TO/8Cu/8Tt/8Cd/8Tf/8C//8T+1qE0d6lKP+jSgIY1oTBOa0ozmtKAlrWhNG9rSjvZ0oCOd6EwXutKN7vSgJ73oTR/60o/+DGAggxjMEIYyjOGMYCSjGM2YUvkMjWVcqfKJHqPH6DF6jB6jx+gxeoweo8foMXqMHqPH6DE1StXP5jth07oTxjOBiUxiMlOYyjSmM4OZzGI2c5jLPOazgIUsYjFLWMoylrOClaxidWU+8RINRUPRUDQUDUVD0VA0FA1FQ9FQNBQNRUOp+C3UUDQUDUVD0VA0FA1FQ9FQNBQNRUPRUDQUDaUaGoqGoqFoKBqKhqKhaCgaioaioWgoGoqGoqFoKBqKhqKhaCgaioaioWgoGoqGoqFoKBqKhqKhVC/r3AlVfaY36v+C9Z41mprLcKgIAAA=","proving_key":[],"verification_key":[],"gates":505501} \ No newline at end of file +{"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"verification_key","type":{"kind":"array","length":114,"type":{"kind":"field"}},"visibility":"private"},{"name":"proof","type":{"kind":"array","length":94,"type":{"kind":"field"}},"visibility":"private"},{"name":"public_inputs","type":{"kind":"array","length":1,"type":{"kind":"field"}},"visibility":"private"},{"name":"key_hash","type":{"kind":"field"},"visibility":"private"},{"name":"input_aggregation_object","type":{"kind":"array","length":16,"type":{"kind":"field"}},"visibility":"private"},{"name":"proof_b","type":{"kind":"array","length":94,"type":{"kind":"field"}},"visibility":"private"}],"param_witnesses":{"input_aggregation_object":[211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226],"key_hash":[210],"proof":[115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208],"proof_b":[227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320],"public_inputs":[209],"verification_key":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114]},"return_type":{"kind":"array","length":16,"type":{"kind":"field"}},"return_witnesses":[337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352]},"bytecode":"H4sIAAAAAAAA/+3WU6/dWQDG4fWObbNj2+7YMx17pmPbtm3Xtm1bX6G2zefk9KZJb5qT9KLpSp6dfbWzk/f3X3uXkkdKKbuVklu4ldu4nTu4k7u4m3u4l/u4nwd4kIeoWTb8bMErZO37LdmKrdmGbdmO7dmBHdmJndmFXSu/d9mdPdiTvdibfdiX/difAziQgziYQziUahzG4RzBkRzF0RzDsRzH8ZzAiZzEyZzCqZzG6ZzBmZzF2ZzDuZzH+VzAhVzExVxCdS7lMi7nCq7kKq7mGq7lOq7nBm7kJm6mBnYrdit2K3Yrdit2K3Yrdit2K3Yrdit2K3Yrdit2KzV5mIoGHuUxHucJnuQpnuYZnuU5nucFXuQlXl67Y8VnvsprvM4bvMlbvM07vMt7vM8HfMhHfMwnfMpnfM4XfMlXfM03fMt3fM8P/MhP/Mwv/Mpv/M4f/Mlf/M0//Mt//E8talOHutSjPg1oSCMa04SmNKM5LWhJK1rThra0oz0d6EgnOtOFrnSjOz3oSS9604e+9KM/AxjIIAYzhKEMYzgjGMkoRjOmVD5DYxlXqnyix+gxeoweo8foMXqMHqPH6DF6jB6jx+gxekyNUvWz+U7YtO6E8UxgIpOYzBSmMo3pzGAms5jNHOYyj/ksYCGLWMwSlrKM5axgJatYXZlPvERD0VA0FA1FQ9FQNBQNRUPRUDQUDUVD0VAqfg81FA1FQ9FQNBQNRUPRUDQUDUVD0VA0FA1FQ6mGhqKhaCgaioaioWgoGoqGoqFoKBqKhqKhaCgaioaioWgoGoqGoqFoKBqKhqKhaCgaioaioWgo1cs6d0JVn+mN/t9gvWcN6fQg96wIAAA=","proving_key":[],"verification_key":[]} \ No newline at end of file