From c25bd08a69ea8f8cf42726d6ebedf9487176171d Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Wed, 3 May 2023 01:11:48 +0530 Subject: [PATCH] c_binds and other ECDSA related fixes (#407) * Add v to stdlib ecdsa. * create an engine if its empty. * Add ecdsa c_bind. * print v as a uint32. * Add secp256k1 cbind. add c_bind.hpp Change hpp to h. remove hpp. * Add ecdsa in cmakelists. remove stdlib_ecdsa from build. --- cpp/src/CMakeLists.txt | 4 ++ cpp/src/barretenberg/crypto/ecdsa/c_bind.cpp | 70 +++++++++++++++++++ cpp/src/barretenberg/crypto/ecdsa/c_bind.h | 29 ++++++++ cpp/src/barretenberg/crypto/ecdsa/ecdsa.hpp | 6 +- .../dsl/acir_format/ecdsa_secp256k1.cpp | 4 +- .../ecc/curves/secp256k1/c_bind.cpp | 30 ++++++++ .../ecc/curves/secp256k1/c_bind.hpp | 12 ++++ .../ecc/groups/affine_element_impl.hpp | 4 ++ .../stdlib/encryption/ecdsa/ecdsa.hpp | 4 ++ .../stdlib/encryption/ecdsa/ecdsa.test.cpp | 5 +- .../stdlib/encryption/ecdsa/ecdsa_impl.hpp | 5 ++ 11 files changed, 169 insertions(+), 4 deletions(-) create mode 100644 cpp/src/barretenberg/crypto/ecdsa/c_bind.cpp create mode 100644 cpp/src/barretenberg/crypto/ecdsa/c_bind.h create mode 100644 cpp/src/barretenberg/ecc/curves/secp256k1/c_bind.cpp create mode 100644 cpp/src/barretenberg/ecc/curves/secp256k1/c_bind.hpp diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index f441c80fa4..69d867a2f7 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -76,6 +76,7 @@ if(WASM) $ $ $ + $ $ $ $ @@ -125,6 +126,7 @@ if(WASM) $ $ $ + $ $ $ $ @@ -179,6 +181,7 @@ if(WASM) $ $ $ + $ $ $ $ @@ -215,6 +218,7 @@ else() $ $ $ + $ $ $ $ diff --git a/cpp/src/barretenberg/crypto/ecdsa/c_bind.cpp b/cpp/src/barretenberg/crypto/ecdsa/c_bind.cpp new file mode 100644 index 0000000000..b7a8d6f5a9 --- /dev/null +++ b/cpp/src/barretenberg/crypto/ecdsa/c_bind.cpp @@ -0,0 +1,70 @@ +#include "ecdsa.hpp" +#include + +#define WASM_EXPORT __attribute__((visibility("default"))) + +extern "C" { + +WASM_EXPORT void ecdsa__compute_public_key(uint8_t const* private_key, uint8_t* public_key_buf) +{ + auto priv_key = from_buffer(private_key); + secp256k1::g1::affine_element pub_key = secp256k1::g1::one * priv_key; + write(public_key_buf, pub_key); +} + +WASM_EXPORT void ecdsa__construct_signature(uint8_t const* message, + size_t msg_len, + uint8_t const* private_key, + uint8_t* output_sig_r, + uint8_t* output_sig_s, + uint8_t* output_sig_v) +{ + using serialize::write; + auto priv_key = from_buffer(private_key); + secp256k1::g1::affine_element pub_key = secp256k1::g1::one * priv_key; + crypto::ecdsa::key_pair key_pair = { priv_key, pub_key }; + + auto sig = crypto::ecdsa::construct_signature( + std::string((char*)message, msg_len), key_pair); + write(output_sig_r, sig.r); + write(output_sig_s, sig.s); + write(output_sig_v, sig.v); +} + +WASM_EXPORT void ecdsa__recover_public_key_from_signature(uint8_t const* message, + size_t msg_len, + uint8_t const* sig_r, + uint8_t const* sig_s, + uint8_t* sig_v, + uint8_t* output_pub_key) +{ + std::array r, s; + std::copy(sig_r, sig_r + 32, r.begin()); + std::copy(sig_s, sig_s + 32, s.begin()); + const uint8_t v = *sig_v; + + crypto::ecdsa::signature sig = { r, s, v }; + auto recovered_pub_key = + crypto::ecdsa::recover_public_key( + std::string((char*)message, msg_len), sig); + write(output_pub_key, recovered_pub_key); +} + +WASM_EXPORT bool ecdsa__verify_signature(uint8_t const* message, + size_t msg_len, + uint8_t const* pub_key, + uint8_t const* sig_r, + uint8_t const* sig_s, + uint8_t const* sig_v) +{ + auto pubk = from_buffer(pub_key); + std::array r, s; + std::copy(sig_r, sig_r + 32, r.begin()); + std::copy(sig_s, sig_s + 32, s.begin()); + const uint8_t v = *sig_v; + + crypto::ecdsa::signature sig = { r, s, v }; + return crypto::ecdsa::verify_signature( + std::string((char*)message, msg_len), pubk, sig); +} +} \ No newline at end of file diff --git a/cpp/src/barretenberg/crypto/ecdsa/c_bind.h b/cpp/src/barretenberg/crypto/ecdsa/c_bind.h new file mode 100644 index 0000000000..897202a372 --- /dev/null +++ b/cpp/src/barretenberg/crypto/ecdsa/c_bind.h @@ -0,0 +1,29 @@ +#include + +#define WASM_EXPORT __attribute__((visibility("default"))) + +extern "C" { + +WASM_EXPORT void ecdsa__compute_public_key(uint8_t const* private_key, uint8_t* public_key_buf); + +WASM_EXPORT void ecdsa__construct_signature(uint8_t const* message, + size_t msg_len, + uint8_t const* private_key, + uint8_t* output_sig_r, + uint8_t* output_sig_s, + uint8_t* output_sig_v); + +WASM_EXPORT void ecdsa__recover_public_key_from_signature(uint8_t const* message, + size_t msg_len, + uint8_t const* sig_r, + uint8_t const* sig_s, + uint8_t* sig_v, + uint8_t* output_pub_key); + +WASM_EXPORT bool ecdsa__verify_signature(uint8_t const* message, + size_t msg_len, + uint8_t const* pub_key, + uint8_t const* sig_r, + uint8_t const* sig_s, + uint8_t const* sig_v); +} diff --git a/cpp/src/barretenberg/crypto/ecdsa/ecdsa.hpp b/cpp/src/barretenberg/crypto/ecdsa/ecdsa.hpp index dea2e18658..57e9074a1b 100644 --- a/cpp/src/barretenberg/crypto/ecdsa/ecdsa.hpp +++ b/cpp/src/barretenberg/crypto/ecdsa/ecdsa.hpp @@ -30,17 +30,18 @@ bool verify_signature(const std::string& message, inline bool operator==(signature const& lhs, signature const& rhs) { - return lhs.r == rhs.r && lhs.s == rhs.s; + return lhs.r == rhs.r && lhs.s == rhs.s && lhs.v == rhs.v; } inline std::ostream& operator<<(std::ostream& os, signature const& sig) { - os << "{ " << sig.r << ", " << sig.s << " }"; + os << "{ " << sig.r << ", " << sig.s << ", " << static_cast(sig.v) << " }"; return os; } template inline void read(B& it, signature& sig) { + using serialize::read; read(it, sig.r); read(it, sig.s); read(it, sig.v); @@ -48,6 +49,7 @@ template inline void read(B& it, signature& sig) template inline void write(B& buf, signature const& sig) { + using serialize::write; write(buf, sig.r); write(buf, sig.s); write(buf, sig.v); diff --git a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp index c18a426e20..21abc4e8e2 100644 --- a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp @@ -96,9 +96,11 @@ void create_ecdsa_verify_constraints(Composer& composer, const EcdsaSecp256k1Con 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(&composer, rr), - stdlib::byte_array(&composer, ss) }; + stdlib::byte_array(&composer, ss), + stdlib::uint8(&composer, vv) }; pub_key_x_fq.assert_is_in_field(); pub_key_y_fq.assert_is_in_field(); diff --git a/cpp/src/barretenberg/ecc/curves/secp256k1/c_bind.cpp b/cpp/src/barretenberg/ecc/curves/secp256k1/c_bind.cpp new file mode 100644 index 0000000000..107d889d4c --- /dev/null +++ b/cpp/src/barretenberg/ecc/curves/secp256k1/c_bind.cpp @@ -0,0 +1,30 @@ +#include "secp256k1.hpp" + +#define WASM_EXPORT __attribute__((visibility("default"))) + +extern "C" { + +WASM_EXPORT void ecc_secp256k1__mul(uint8_t const* point_buf, uint8_t const* scalar_buf, uint8_t* result) +{ + auto point = from_buffer(point_buf); + auto scalar = from_buffer(scalar_buf); + secp256k1::g1::affine_element r = point * scalar; + write(result, r); +} + +WASM_EXPORT void ecc_secp256k1__get_random_scalar_mod_circuit_modulus(uint8_t* result) +{ + barretenberg::fr output = barretenberg::fr::random_element(); + write(result, output); +} + +WASM_EXPORT void ecc_secp256k1__reduce512_buffer_mod_circuit_modulus(uint8_t* input, uint8_t* result) +{ + uint512_t bigint_input = from_buffer(input); + + uint512_t barretenberg_modulus(barretenberg::fr::modulus); + + uint512_t target_output = bigint_input % barretenberg_modulus; + write(result, target_output.lo); +} +} \ No newline at end of file diff --git a/cpp/src/barretenberg/ecc/curves/secp256k1/c_bind.hpp b/cpp/src/barretenberg/ecc/curves/secp256k1/c_bind.hpp new file mode 100644 index 0000000000..b1b1983239 --- /dev/null +++ b/cpp/src/barretenberg/ecc/curves/secp256k1/c_bind.hpp @@ -0,0 +1,12 @@ +#include "secp256k1.hpp" + +#define WASM_EXPORT __attribute__((visibility("default"))) + +extern "C" { + +WASM_EXPORT void ecc_secp256k1__mul(uint8_t const* point_buf, uint8_t const* scalar_buf, uint8_t* result); + +WASM_EXPORT void ecc_secp256k1__get_random_scalar_mod_circuit_modulus(uint8_t* result); + +WASM_EXPORT void ecc_secp256k1__reduce512_buffer_mod_circuit_modulus(uint8_t* input, uint8_t* result); +} diff --git a/cpp/src/barretenberg/ecc/groups/affine_element_impl.hpp b/cpp/src/barretenberg/ecc/groups/affine_element_impl.hpp index b685bc05a0..c1e61e729f 100644 --- a/cpp/src/barretenberg/ecc/groups/affine_element_impl.hpp +++ b/cpp/src/barretenberg/ecc/groups/affine_element_impl.hpp @@ -233,6 +233,10 @@ affine_element affine_element::hash_to_curve(const uint64_ template affine_element affine_element::random_element(numeric::random::Engine* engine) noexcept { + if (engine == nullptr) { + engine = &numeric::random::get_engine(); + } + bool found_one = false; Fq yy; Fq x; diff --git a/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp b/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp index 1864557af4..ea5f890fd5 100644 --- a/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp +++ b/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp @@ -2,6 +2,7 @@ #include "barretenberg/crypto/ecdsa/ecdsa.hpp" #include "../../primitives/byte_array/byte_array.hpp" +#include "../../primitives/uint/uint.hpp" #include "../../primitives/composers/composers_fwd.hpp" namespace proof_system::plonk { @@ -11,6 +12,7 @@ namespace ecdsa { template struct signature { stdlib::byte_array r; stdlib::byte_array s; + stdlib::uint8 v; }; template @@ -25,9 +27,11 @@ static signature from_witness(Composer* ctx, const crypto::ecdsa::sign std::vector s_vec(std::begin(input.s), std::end(input.s)); stdlib::byte_array r(ctx, r_vec); stdlib::byte_array s(ctx, s_vec); + stdlib::uint8 v(ctx, input.v); signature out; out.r = r; out.s = s; + out.v = v; return out; } diff --git a/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.test.cpp b/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.test.cpp index b1edc24d84..405d28f33c 100644 --- a/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.test.cpp +++ b/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.test.cpp @@ -35,8 +35,11 @@ TEST(stdlib_ecdsa, verify_signature) std::vector rr(signature.r.begin(), signature.r.end()); std::vector ss(signature.s.begin(), signature.s.end()); + uint8_t vv = signature.v; - stdlib::ecdsa::signature sig{ curve::byte_array_ct(&composer, rr), curve::byte_array_ct(&composer, ss) }; + stdlib::ecdsa::signature sig{ curve::byte_array_ct(&composer, rr), + curve::byte_array_ct(&composer, ss), + stdlib::uint8(&composer, vv) }; curve::byte_array_ct message(&composer, message_string); diff --git a/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp b/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp index 12355453d6..4262555396 100644 --- a/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp +++ b/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp @@ -13,6 +13,11 @@ bool_t verify_signature(const stdlib::byte_array& message, { Composer* ctx = message.get_context() ? message.get_context() : public_key.x.context; + // Check if revovery id v is either 27 ot 28. + // TODO(Suyash): check with Zac/Kesha/Cody. + field_t(sig.v).assert_is_in_set({ field_t(27), field_t(28) }, + "signature is non-standard"); + stdlib::byte_array hashed_message = static_cast>(stdlib::sha256(message));