Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <gtest/gtest.h>
#include <vector>
#include "barretenberg/common/streams.hpp"
#include "ecdsa_secp256k1.hpp"

TEST(acir_format, test_logic_gate_from_noir_circuit)
{
Expand Down
25 changes: 17 additions & 8 deletions cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ crypto::ecdsa::signature ecdsa_convert_signature(Composer& composer, std::vector
signature_cr.s[i - 32] = fr_bytes.back();
}

signature_cr.v = 27;

return signature_cr;
}

Expand Down Expand Up @@ -104,17 +106,24 @@ void create_ecdsa_verify_constraints(Composer& composer, const EcdsaSecp256k1Con

pub_key_x_fq.assert_is_in_field();
pub_key_y_fq.assert_is_in_field();

secp256k1_ct::g1_bigfr_ct public_key = secp256k1_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(&composer, input.signature[i]));
sig.s[i].assert_equal(field_ct::from_witness_index(&composer, input.signature[i + 32]));
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]));
}

bool_ct signature_result = stdlib::ecdsa::verify_signature<Composer,
secp256k1_ct,
secp256k1_ct::fq_ct,
secp256k1_ct::bigfr_ct,
secp256k1_ct::g1_bigfr_ct>(message, public_key, sig);

bool_ct signature_result =
stdlib::ecdsa::verify_signature_noassert<Composer,
secp256k1_ct,
secp256k1_ct::fq_ct,
secp256k1_ct::bigfr_ct,
secp256k1_ct::g1_bigfr_ct>(message, public_key, sig);
bool_ct signature_result_normalized = signature_result.normalize();

composer.assert_equal(signature_result_normalized.witness_index, input.result);
}

Expand Down
144 changes: 144 additions & 0 deletions cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#include "acir_format.hpp"
#include "ecdsa_secp256k1.hpp"
#include "barretenberg/plonk/proof_system/types/proof.hpp"
#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp"
#include "barretenberg/crypto/ecdsa/ecdsa.hpp"

#include <gtest/gtest.h>
#include <vector>

using curve = proof_system::plonk::stdlib::secp256k1<acir_format::Composer>;

size_t generate_ecdsa_constraint(acir_format::EcdsaSecp256k1Constraint& ecdsa_constraint,
std::vector<fr>& witness_values)
{
std::string message_string = "Instructions unclear, ask again later.";

crypto::ecdsa::key_pair<curve::fr, curve::g1> account;
account.private_key = curve::fr::random_element();
account.public_key = curve::g1::one * account.private_key;

crypto::ecdsa::signature signature =
crypto::ecdsa::construct_signature<Sha256Hasher, curve::fq, curve::fr, curve::g1>(message_string, account);

uint256_t pub_x_value = account.public_key.x;
uint256_t pub_y_value = account.public_key.y;

std::vector<uint32_t> message_in;
std::vector<uint32_t> pub_x_indices_in;
std::vector<uint32_t> pub_y_indices_in;
std::vector<uint32_t> signature_in;
size_t offset = 1;
for (size_t i = 0; i < message_string.size(); ++i) {
message_in.emplace_back(i + offset);
const auto byte = static_cast<uint8_t>(message_string[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<uint32_t>(offset);
offset += 1;
witness_values.emplace_back(1);

ecdsa_constraint = acir_format::EcdsaSecp256k1Constraint{
.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;
}

TEST(ECDSASecp256k1, TestECDSAConstraintSucceed)
{
acir_format::EcdsaSecp256k1Constraint ecdsa_constraint;
std::vector<fr> witness_values;
size_t num_variables = generate_ecdsa_constraint(ecdsa_constraint, witness_values);
acir_format::acir_format constraint_system{
.varnum = static_cast<uint32_t>(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 composer = acir_format::create_circuit_with_witness(constraint_system, witness_values);

EXPECT_EQ(composer.get_variable(ecdsa_constraint.result), 1);
auto prover = composer.create_prover();

auto proof = prover.construct_proof();
auto verifier = composer.create_verifier();
EXPECT_EQ(verifier.verify_proof(proof), true);
}

TEST(ECDSASecp256k1, TestECDSAConstraintFail)
{
acir_format::EcdsaSecp256k1Constraint ecdsa_constraint;
std::vector<fr> witness_values;
size_t num_variables = generate_ecdsa_constraint(ecdsa_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::acir_format constraint_system{
.varnum = static_cast<uint32_t>(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 composer = acir_format::create_circuit_with_witness(constraint_system, witness_values);

EXPECT_EQ(composer.get_variable(ecdsa_constraint.result), 0);
auto prover = composer.create_prover();

auto proof = prover.construct_proof();
auto verifier = composer.create_verifier();
EXPECT_EQ(verifier.verify_proof(proof), true);
}
5 changes: 5 additions & 0 deletions cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ bool_t<Composer> verify_signature(const stdlib::byte_array<Composer>& message,
const G1& public_key,
const signature<Composer>& sig);

template <typename Composer, typename Curve, typename Fq, typename Fr, typename G1>
bool_t<Composer> verify_signature_noassert(const stdlib::byte_array<Composer>& message,
const G1& public_key,
const signature<Composer>& sig);

template <typename Composer>
static signature<Composer> from_witness(Composer* ctx, const crypto::ecdsa::signature& input)
{
Expand Down
94 changes: 94 additions & 0 deletions cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,98 @@ TEST(stdlib_ecdsa, verify_signature)
bool proof_result = verifier.verify_proof(proof);
EXPECT_EQ(proof_result, true);
}

TEST(stdlib_ecdsa, verify_signature_noassert_succeed)
{
Composer composer = Composer();

// whaaablaghaaglerijgeriij
std::string message_string = "Instructions unclear, ask again later.";

crypto::ecdsa::key_pair<curve::fr, curve::g1> account;
account.private_key = curve::fr::random_element();
account.public_key = curve::g1::one * account.private_key;

crypto::ecdsa::signature signature =
crypto::ecdsa::construct_signature<Sha256Hasher, curve::fq, curve::fr, curve::g1>(message_string, account);

bool first_result = crypto::ecdsa::verify_signature<Sha256Hasher, curve::fq, curve::fr, curve::g1>(
message_string, account.public_key, signature);
EXPECT_EQ(first_result, true);

curve::g1_bigfr_ct public_key = curve::g1_bigfr_ct::from_witness(&composer, account.public_key);

std::vector<uint8_t> rr(signature.r.begin(), signature.r.end());
std::vector<uint8_t> ss(signature.s.begin(), signature.s.end());
uint8_t vv = signature.v;

stdlib::ecdsa::signature<Composer> sig{
curve::byte_array_ct(&composer, rr),
curve::byte_array_ct(&composer, ss),
stdlib::uint8<Composer>(&composer, vv),
};

curve::byte_array_ct message(&composer, message_string);

curve::bool_ct signature_result =
stdlib::ecdsa::verify_signature_noassert<Composer, curve, curve::fq_ct, curve::bigfr_ct, curve::g1_bigfr_ct>(
message, public_key, sig);

EXPECT_EQ(signature_result.get_value(), true);

std::cerr << "composer gates = " << composer.get_num_gates() << std::endl;
benchmark_info("UltraComposer", "ECDSA", "Signature Verification Test", "Gate Count", composer.get_num_gates());
auto prover = composer.create_prover();
auto verifier = composer.create_verifier();
auto proof = prover.construct_proof();
bool proof_result = verifier.verify_proof(proof);
EXPECT_EQ(proof_result, true);
}

TEST(stdlib_ecdsa, verify_signature_noassert_fail)
{
Composer composer = Composer();

// whaaablaghaaglerijgeriij
std::string message_string = "Instructions unclear, ask again later.";

crypto::ecdsa::key_pair<curve::fr, curve::g1> account;
account.private_key = curve::fr::random_element();
account.public_key = curve::g1::one * account.private_key;

crypto::ecdsa::signature signature =
crypto::ecdsa::construct_signature<Sha256Hasher, curve::fq, curve::fr, curve::g1>(message_string, account);

// tamper w. signature to make fail
signature.r[0] += 1;

bool first_result = crypto::ecdsa::verify_signature<Sha256Hasher, curve::fq, curve::fr, curve::g1>(
message_string, account.public_key, signature);
EXPECT_EQ(first_result, false);

curve::g1_bigfr_ct public_key = curve::g1_bigfr_ct::from_witness(&composer, account.public_key);

std::vector<uint8_t> rr(signature.r.begin(), signature.r.end());
std::vector<uint8_t> ss(signature.s.begin(), signature.s.end());

stdlib::ecdsa::signature<Composer> sig{ curve::byte_array_ct(&composer, rr),
curve::byte_array_ct(&composer, ss),
27 };

curve::byte_array_ct message(&composer, message_string);

curve::bool_ct signature_result =
stdlib::ecdsa::verify_signature_noassert<Composer, curve, curve::fq_ct, curve::bigfr_ct, curve::g1_bigfr_ct>(
message, public_key, sig);

EXPECT_EQ(signature_result.get_value(), false);

std::cerr << "composer gates = " << composer.get_num_gates() << std::endl;
benchmark_info("UltraComposer", "ECDSA", "Signature Verification Test", "Gate Count", composer.get_num_gates());
auto prover = composer.create_prover();
auto verifier = composer.create_verifier();
auto proof = prover.construct_proof();
bool proof_result = verifier.verify_proof(proof);
EXPECT_EQ(proof_result, true);
}
} // namespace test_stdlib_ecdsa
Loading