barretenberg
Loading...
Searching...
No Matches
ecdsa_impl.hpp
1#pragma once
2
3#include "barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp"
4#include "barretenberg/stdlib/hash/sha256/sha256.hpp"
5#include "barretenberg/stdlib/primitives//bit_array/bit_array.hpp"
6
7namespace proof_system::plonk {
8namespace stdlib {
9namespace ecdsa {
10
24template <typename Builder, typename Curve, typename Fq, typename Fr, typename G1>
25bool_t<Builder> verify_signature(const stdlib::byte_array<Builder>& message,
26 const G1& public_key,
27 const signature<Builder>& sig)
28{
29 Builder* ctx = message.get_context() ? message.get_context() : public_key.x.context;
30
58 // Note: This check is also present in the _noassert variation of this method.
59 field_t<Builder>(sig.v).assert_is_in_set({ field_t<Builder>(27), field_t<Builder>(28) },
60 "signature is non-standard");
61
62 stdlib::byte_array<Builder> hashed_message =
63 static_cast<stdlib::byte_array<Builder>>(stdlib::sha256<Builder>(message));
64
65 Fr z(hashed_message);
66 z.assert_is_in_field();
67
68 Fr r(sig.r);
69 // force r to be < secp256k1 group modulus, so we can compare with `result_mod_r` below
70 r.assert_is_in_field();
71
72 Fr s(sig.s);
73
74 // r and s should not be zero
75 r.assert_is_not_equal(Fr::zero());
76 s.assert_is_not_equal(Fr::zero());
77
78 // s should be less than |Fr| / 2
79 // Read more about this at: https://www.derpturkey.com/inherent-malleability-of-ecdsa-signatures/amp/
80 s.assert_less_than((Fr::modulus + 1) / 2);
81
82 Fr u1 = z / s;
83 Fr u2 = r / s;
84
85 public_key.validate_on_curve();
86
87 G1 result;
88 // TODO(Cody): Having Plookup should not determine which curve is used.
89 // Use special plookup secp256k1 ECDSA mul if available (this relies on k1 endomorphism, and cannot be used for
90 // other curves)
91 if constexpr (HasPlookup<Builder> && Curve::type == proof_system::CurveType::SECP256K1) {
92 result = G1::secp256k1_ecdsa_mul(public_key, u1, u2);
93 } else {
94 result = G1::batch_mul({ G1::one(ctx), public_key }, { u1, u2 });
95 }
96 result.x.self_reduce();
97
98 // transfer Fq value x to an Fr element and reduce mod r
99 Fr result_mod_r(ctx, 0);
100 result_mod_r.binary_basis_limbs[0].element = result.x.binary_basis_limbs[0].element;
101 result_mod_r.binary_basis_limbs[1].element = result.x.binary_basis_limbs[1].element;
102 result_mod_r.binary_basis_limbs[2].element = result.x.binary_basis_limbs[2].element;
103 result_mod_r.binary_basis_limbs[3].element = result.x.binary_basis_limbs[3].element;
104 result_mod_r.binary_basis_limbs[0].maximum_value = result.x.binary_basis_limbs[0].maximum_value;
105 result_mod_r.binary_basis_limbs[1].maximum_value = result.x.binary_basis_limbs[1].maximum_value;
106 result_mod_r.binary_basis_limbs[2].maximum_value = result.x.binary_basis_limbs[2].maximum_value;
107 result_mod_r.binary_basis_limbs[3].maximum_value = result.x.binary_basis_limbs[3].maximum_value;
108
109 result_mod_r.prime_basis_limb = result.x.prime_basis_limb;
110
111 result_mod_r.assert_is_in_field();
112
113 result_mod_r.binary_basis_limbs[0].element.assert_equal(r.binary_basis_limbs[0].element);
114 result_mod_r.binary_basis_limbs[1].element.assert_equal(r.binary_basis_limbs[1].element);
115 result_mod_r.binary_basis_limbs[2].element.assert_equal(r.binary_basis_limbs[2].element);
116 result_mod_r.binary_basis_limbs[3].element.assert_equal(r.binary_basis_limbs[3].element);
117 result_mod_r.prime_basis_limb.assert_equal(r.prime_basis_limb);
118 return bool_t<Builder>(ctx, true);
119}
120
134template <typename Builder, typename Curve, typename Fq, typename Fr, typename G1>
135bool_t<Builder> verify_signature_prehashed_message_noassert(const stdlib::byte_array<Builder>& hashed_message,
136 const G1& public_key,
137 const signature<Builder>& sig)
138{
139 Builder* ctx = hashed_message.get_context() ? hashed_message.get_context() : public_key.x.context;
140
141 Fr z(hashed_message);
142 z.assert_is_in_field();
143
144 Fr r(sig.r);
145 // force r to be < secp256k1 group modulus, so we can compare with `result_mod_r` below
146 r.assert_is_in_field();
147
148 Fr s(sig.s);
149
150 // r and s should not be zero
151 r.assert_is_not_equal(Fr::zero());
152 s.assert_is_not_equal(Fr::zero());
153
154 // s should be less than |Fr| / 2
155 // Read more about this at: https://www.derpturkey.com/inherent-malleability-of-ecdsa-signatures/amp/
156 s.assert_less_than((Fr::modulus + 1) / 2);
157
158 Fr u1 = z / s;
159 Fr u2 = r / s;
160
161 public_key.validate_on_curve();
162
163 G1 result;
164 // Use special plookup secp256k1 ECDSA mul if available (this relies on k1 endomorphism, and cannot be used for
165 // other curves)
166 if constexpr (HasPlookup<Builder> && Curve::type == proof_system::CurveType::SECP256K1) {
167 result = G1::secp256k1_ecdsa_mul(public_key, u1, u2);
168 } else {
169 result = G1::batch_mul({ G1::one(ctx), public_key }, { u1, u2 });
170 }
171 result.x.self_reduce();
172
173 // transfer Fq value x to an Fr element and reduce mod r
174 Fr result_mod_r(ctx, 0);
175 result_mod_r.binary_basis_limbs[0].element = result.x.binary_basis_limbs[0].element;
176 result_mod_r.binary_basis_limbs[1].element = result.x.binary_basis_limbs[1].element;
177 result_mod_r.binary_basis_limbs[2].element = result.x.binary_basis_limbs[2].element;
178 result_mod_r.binary_basis_limbs[3].element = result.x.binary_basis_limbs[3].element;
179 result_mod_r.binary_basis_limbs[0].maximum_value = result.x.binary_basis_limbs[0].maximum_value;
180 result_mod_r.binary_basis_limbs[1].maximum_value = result.x.binary_basis_limbs[1].maximum_value;
181 result_mod_r.binary_basis_limbs[2].maximum_value = result.x.binary_basis_limbs[2].maximum_value;
182 result_mod_r.binary_basis_limbs[3].maximum_value = result.x.binary_basis_limbs[3].maximum_value;
183
184 result_mod_r.prime_basis_limb = result.x.prime_basis_limb;
185
186 result_mod_r.assert_is_in_field();
187
188 bool_t<Builder> output(ctx, true);
189 output &= result_mod_r.binary_basis_limbs[0].element == (r.binary_basis_limbs[0].element);
190 output &= result_mod_r.binary_basis_limbs[1].element == (r.binary_basis_limbs[1].element);
191 output &= result_mod_r.binary_basis_limbs[2].element == (r.binary_basis_limbs[2].element);
192 output &= result_mod_r.binary_basis_limbs[3].element == (r.binary_basis_limbs[3].element);
193 output &= result_mod_r.prime_basis_limb == (r.prime_basis_limb);
194
195 field_t<Builder>(sig.v).assert_is_in_set({ field_t<Builder>(27), field_t<Builder>(28) },
196 "signature is non-standard");
197
198 return output;
199}
200
214template <typename Builder, typename Curve, typename Fq, typename Fr, typename G1>
215bool_t<Builder> verify_signature_noassert(const stdlib::byte_array<Builder>& message,
216 const G1& public_key,
217 const signature<Builder>& sig)
218{
219 stdlib::byte_array<Builder> hashed_message =
220 static_cast<stdlib::byte_array<Builder>>(stdlib::sha256<Builder>(message));
221
222 return verify_signature_prehashed_message_noassert<Builder, Curve, Fq, Fr, G1>(hashed_message, public_key, sig);
223}
224
225} // namespace ecdsa
226} // namespace stdlib
227} // namespace proof_system::plonk
Definition: standard_circuit_builder.hpp:12
Definition: field.hpp:10
Contains all the headers required to adequately compile the types defined in circuit_builders_fwd....
Definition: circuit_builders.hpp:11
Definition: widget.bench.cpp:13