Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ecdsa_constraints.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
12
13namespace acir_format {
14
15using namespace bb;
16
37template <typename Curve>
38void create_ecdsa_verify_constraints(typename Curve::Builder& builder,
39 const EcdsaConstraint& input,
40 bool has_valid_witness_assignments)
41{
42 using Builder = Curve::Builder;
43
44 using Fq = Curve::fq_ct;
45 using Fr = Curve::bigfr_ct;
46 using G1 = Curve::g1_bigfr_ct;
47
51
52 // Lambda to convert std::vector<field_ct> to byte_array_ct
53 auto fields_to_bytes = [](Builder& builder, std::vector<field_ct>& fields) -> byte_array_ct {
54 byte_array_ct result(&builder);
55 for (auto& field : fields) {
56 // Construct byte array of length 1 from the field element
57 // The constructor enforces that `field` fits in one byte
58 byte_array_ct byte_to_append(field, /*num_bytes=*/1);
59 // Append the new byte to the result
60 result.write(byte_to_append);
61 }
62
63 return result;
64 };
65
66 // Define builder variables based on the witness indices
67 std::vector<field_ct> hashed_message_fields = fields_from_witnesses(builder, input.hashed_message);
68 std::vector<field_ct> r_fields = fields_from_witnesses(builder, std::span(input.signature.begin(), 32));
69 std::vector<field_ct> s_fields = fields_from_witnesses(builder, std::span(input.signature.begin() + 32, 32));
70 std::vector<field_ct> pub_x_fields = fields_from_witnesses(builder, input.pub_x_indices);
71 std::vector<field_ct> pub_y_fields = fields_from_witnesses(builder, input.pub_y_indices);
73
74 if (!has_valid_witness_assignments) {
75 // Fill builder variables in case of empty witness assignment
76 create_dummy_ecdsa_constraint<Curve>(
77 builder, hashed_message_fields, r_fields, s_fields, pub_x_fields, pub_y_fields, result_field);
78 }
79
80 // Step 1.
81 // Construct inputs to signature verification from witness indices
82 byte_array_ct hashed_message = fields_to_bytes(builder, hashed_message_fields);
83 byte_array_ct pub_x_bytes = fields_to_bytes(builder, pub_x_fields);
84 byte_array_ct pub_y_bytes = fields_to_bytes(builder, pub_y_fields);
85 byte_array_ct r = fields_to_bytes(builder, r_fields);
86 byte_array_ct s = fields_to_bytes(builder, s_fields);
87 bool_ct result = static_cast<bool_ct>(result_field); // Constructor enforces result_field = 0 or 1
88
89 // Step 2.
90 // Reconstruct the public key from the byte representations of its coordinates
91 Fq pub_x(pub_x_bytes);
92 Fq pub_y(pub_y_bytes);
93 G1 public_key(pub_x, pub_y);
94
95 // Step 3.
96 // Ensure uniqueness of the public key by asserting each of its coordinates is smaller than the modulus of the base
97 // field
98 pub_x.assert_is_in_field();
99 pub_y.assert_is_in_field();
100
101 // Step 4.
102 bool_ct signature_result =
103 stdlib::ecdsa_verify_signature<Builder, Curve, Fq, Fr, G1>(hashed_message, public_key, { r, s });
104
105 // Step 5.
106 // Assert that signature verification returned the expected result
107 signature_result.assert_equal(result);
108}
109
115template <typename Curve>
116void create_dummy_ecdsa_constraint(typename Curve::Builder& builder,
117 const std::vector<stdlib::field_t<typename Curve::Builder>>& hashed_message_fields,
118 const std::vector<stdlib::field_t<typename Curve::Builder>>& r_fields,
119 const std::vector<stdlib::field_t<typename Curve::Builder>>& s_fields,
120 const std::vector<stdlib::field_t<typename Curve::Builder>>& pub_x_fields,
121 const std::vector<stdlib::field_t<typename Curve::Builder>>& pub_y_fields,
123{
124 using Builder = Curve::Builder;
125 using FqNative = Curve::fq;
126 using G1Native = Curve::g1;
128
129 // Lambda to populate builder variables from vector of field values
130 auto populate_fields = [&builder](const std::vector<field_ct>& fields, const std::vector<bb::fr>& values) {
131 for (auto [field, value] : zip_view(fields, values)) {
132 builder.set_variable(field.witness_index, value);
133 }
134 };
135
136 // Vector of 32 copies of bb::fr::zero()
137 std::vector<bb::fr> mock_zeros(32, bb::fr::zero());
138
139 // Hashed message
140 populate_fields(hashed_message_fields, mock_zeros);
141
142 // Signature
143 populate_fields(r_fields, mock_zeros);
144 populate_fields(s_fields, mock_zeros);
145
146 // Pub key
147 std::array<uint8_t, 32> buffer_x;
148 std::array<uint8_t, 32> buffer_y;
149 std::vector<bb::fr> mock_pub_x;
150 std::vector<bb::fr> mock_pub_y;
151 FqNative::serialize_to_buffer(G1Native::one.x, &buffer_x[0]);
152 FqNative::serialize_to_buffer(G1Native::one.y, &buffer_y[0]);
153 for (auto [byte_x, byte_y] : zip_view(buffer_x, buffer_y)) {
154 mock_pub_x.emplace_back(bb::fr(byte_x));
155 mock_pub_y.emplace_back(bb::fr(byte_y));
156 }
157 populate_fields(pub_x_fields, mock_pub_x);
158 populate_fields(pub_y_fields, mock_pub_y);
159
160 // Result
161 builder.set_variable(result_field.witness_index, bb::fr::one());
162}
163
164template void create_ecdsa_verify_constraints<stdlib::secp256k1<UltraCircuitBuilder>>(
165 UltraCircuitBuilder& builder, const EcdsaConstraint& input, bool has_valid_witness_assignments);
166template void create_ecdsa_verify_constraints<stdlib::secp256k1<MegaCircuitBuilder>>(
167 MegaCircuitBuilder& builder, const EcdsaConstraint& input, bool has_valid_witness_assignments);
168template void create_ecdsa_verify_constraints<stdlib::secp256r1<UltraCircuitBuilder>>(
169 UltraCircuitBuilder& builder, const EcdsaConstraint& input, bool has_valid_witness_assignments);
170template void create_ecdsa_verify_constraints<stdlib::secp256r1<MegaCircuitBuilder>>(
171 MegaCircuitBuilder& builder, const EcdsaConstraint& input, bool has_valid_witness_assignments);
172
173template void create_dummy_ecdsa_constraint<stdlib::secp256k1<UltraCircuitBuilder>>(
181
182template void create_dummy_ecdsa_constraint<stdlib::secp256r1<UltraCircuitBuilder>>(
190
191} // namespace acir_format
Implements boolean logic in-circuit.
Definition bool.hpp:59
void assert_equal(const bool_t &rhs, std::string const &msg="bool_t::assert_equal") const
Implements copy constraint for bool_t elements.
Definition bool.cpp:396
Represents a dynamic array of bytes in-circuit.
byte_array & write(byte_array const &other)
Appends the contents of another byte_array (other) to the end of this one.
static field_t from_witness_index(Builder *ctx, uint32_t witness_index)
Definition field.cpp:59
uint32_t witness_index
Definition field.hpp:132
AluTraceBuilder builder
Definition alu.test.cpp:123
void create_ecdsa_verify_constraints(typename Curve::Builder &builder, const EcdsaConstraint &input, bool has_valid_witness_assignments)
Create constraints to verify an ECDSA signature.
void create_dummy_ecdsa_constraint(typename Curve::Builder &builder, const std::vector< stdlib::field_t< typename Curve::Builder > > &hashed_message_fields, const std::vector< stdlib::field_t< typename Curve::Builder > > &r_fields, const std::vector< stdlib::field_t< typename Curve::Builder > > &s_fields, const std::vector< stdlib::field_t< typename Curve::Builder > > &pub_x_fields, const std::vector< stdlib::field_t< typename Curve::Builder > > &pub_y_fields, const stdlib::field_t< typename Curve::Builder > &result_field)
Generate dummy ECDSA constraints when the builder doesn't have witnesses.
Entry point for Barretenberg command-line interface.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::AffineElement G1
std::array< uint32_t, 32 > pub_x_indices
std::array< uint32_t, 32 > hashed_message
std::array< uint32_t, 64 > signature
std::array< uint32_t, 32 > pub_y_indices
static constexpr field one()
static constexpr field zero()