Skip to content

Commit 3930f2f

Browse files
authored
Merge pull request #1889 from evoskuil/master
Make signature batch verify cancellable.
2 parents c8c59b4 + 0cc355a commit 3930f2f

4 files changed

Lines changed: 91 additions & 62 deletions

File tree

include/bitcoin/system/crypto/secp256k1_batch.hpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,19 @@ namespace schnorr {
4343
struct BC_API batch
4444
{
4545
using span = std::span<const batch>;
46-
static batchy::links_t verify(const span& batch, bool turbo) NOEXCEPT;
46+
static batchy::links_t verify(const stopper& cancel,
47+
const span& batch) NOEXCEPT;
4748

4849
hash_digest digest;
4950
ec_xonly point;
5051
ec_signature signature;
5152
batchy::link id;
5253

5354
protected:
54-
static data_chunk evaluate(const span& batch, bool turbo) NOEXCEPT;
55-
static batchy::links_t correlate(const data_chunk& out,
55+
static data_chunk evaluate(const stopper& cancel,
5656
const span& batch) NOEXCEPT;
57+
static batchy::links_t correlate(const stopper& cancel,
58+
const data_chunk& out, const span& batch) NOEXCEPT;
5759
};
5860

5961
} // namespace schnorr
@@ -64,7 +66,8 @@ namespace threshold {
6466
struct BC_API batch
6567
{
6668
using span = std::span<const batch>;
67-
static batchy::links_t verify(const span& batch, bool turbo) NOEXCEPT;
69+
static batchy::links_t verify(const stopper& cancel,
70+
const span& batch) NOEXCEPT;
6871

6972
hash_digest digest;
7073
ec_xonly point;
@@ -74,9 +77,10 @@ struct BC_API batch
7477
batchy::link id;
7578

7679
protected:
77-
static data_chunk evaluate(const span& batch, bool turbo) NOEXCEPT;
78-
static batchy::links_t correlate(const data_chunk& out,
80+
static data_chunk evaluate(const stopper& cancel,
7981
const span& batch) NOEXCEPT;
82+
static batchy::links_t correlate(const stopper& cancel,
83+
const data_chunk& out, const span& batch) NOEXCEPT;
8084
};
8185

8286
} // namespace threshold
@@ -87,17 +91,19 @@ namespace ecdsa {
8791
struct BC_API batch
8892
{
8993
using span = std::span<const batch>;
90-
static batchy::links_t verify(const span& batch, bool turbo) NOEXCEPT;
94+
static batchy::links_t verify(const stopper& cancel,
95+
const span& batch) NOEXCEPT;
9196

9297
hash_digest digest;
9398
ec_compressed point;
9499
ec_signature signature;
95100
batchy::link id;
96101

97102
protected:
98-
static data_chunk evaluate(const span& batch, bool turbo) NOEXCEPT;
99-
static batchy::links_t correlate(const data_chunk& out,
103+
static data_chunk evaluate(const stopper& cancel,
100104
const span& batch) NOEXCEPT;
105+
static batchy::links_t correlate(const stopper& cancel,
106+
const data_chunk& out, const span& batch) NOEXCEPT;
101107
};
102108

103109
} // namespace ecdsa
@@ -108,7 +114,8 @@ namespace multisig {
108114
struct BC_API batch
109115
{
110116
using span = std::span<const batch>;
111-
static batchy::links_t verify(const span& batch, bool turbo) NOEXCEPT;
117+
static batchy::links_t verify(const stopper& cancel,
118+
const span& batch) NOEXCEPT;
112119

113120
hash_digest digest;
114121
ec_compressed point;
@@ -118,9 +125,10 @@ struct BC_API batch
118125
batchy::link id;
119126

120127
protected:
121-
static data_chunk evaluate(const span& batch, bool turbo) NOEXCEPT;
122-
static batchy::links_t correlate(const data_chunk& out,
128+
static data_chunk evaluate(const stopper& cancel,
123129
const span& batch) NOEXCEPT;
130+
static batchy::links_t correlate(const stopper& cancel,
131+
const data_chunk& out, const span& batch) NOEXCEPT;
124132
};
125133

126134
} // namespace multisig

include/bitcoin/system/types.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ using iif = std::conditional_t<Condition, IfTrue, IfFalse>;
5757
template <size_t Position, typename ...Args>
5858
using argument = std::tuple_element_t<Position, std::tuple<Args...>>;
5959

60+
/// Used for cancellation, see also std::std::stop_token.
61+
using stopper = std::atomic_bool;
62+
6063
/// Define signed_size_t
6164
/// ---------------------------------------------------------------------------
6265

src/crypto/secp256k1/batch.cpp

Lines changed: 56 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,11 @@ BC_PUSH_WARNING(NO_ARRAY_INDEXING)
7373
// ----------------------------------------------------------------------------
7474

7575
#if defined(HAVE_ULTRAFAST)
76-
76+
77+
// TODO: pass cancel.
7778
template <typename Batch>
78-
data_chunk batch_verify(const std::span<Batch>& batch, bool) NOEXCEPT
79+
data_chunk batch_verify(const stopper& /* cancel */,
80+
const std::span<Batch>& batch) NOEXCEPT
7981
{
8082
// OOM is unrecoverable.
8183
static thread_local ufsecp::lbtc::Controller context{ UFSECP_LBTC_AUTO };
@@ -103,7 +105,8 @@ data_chunk batch_verify(const std::span<Batch>& batch, bool) NOEXCEPT
103105
#else
104106

105107
template <typename Batch>
106-
data_chunk batch_verify(const std::span<Batch>& batch, bool) NOEXCEPT
108+
data_chunk batch_verify(const stopper& cancel,
109+
const std::span<Batch>& batch) NOEXCEPT
107110
{
108111
constexpr auto policy = poolstl::execution::par;
109112

@@ -115,6 +118,7 @@ data_chunk batch_verify(const std::span<Batch>& batch, bool) NOEXCEPT
115118
data_chunk results(batch.size());
116119
std::for_each(policy, it.cbegin(), it.cend(), [&](size_t row) NOEXCEPT
117120
{
121+
if (cancel) return;
118122
results.at(row) = to_int<uint8_t>(verify_signature(batch[row]));
119123
});
120124

@@ -159,7 +163,7 @@ inline bool has_valid_path(uint8_t m_sigs, uint8_t n_keys,
159163

160164
// Trivial single signature correlation.
161165
template <typename Batch>
162-
links_t to_links(const data_chunk& out,
166+
links_t to_links(const stopper& cancel, const data_chunk& out,
163167
const std::span<const Batch>& in) NOEXCEPT
164168
{
165169
BC_ASSERT(out.size() == in.size());
@@ -174,6 +178,8 @@ links_t to_links(const data_chunk& out,
174178
std::for_each(poolstl::execution::par, it.cbegin(), it.cend(),
175179
[&](size_t row) NOEXCEPT
176180
{
181+
if (cancel) return;
182+
177183
// Failure is *extremely* rare, so this is very efficient.
178184
if (!to_bool(out.at(row)))
179185
{
@@ -188,8 +194,8 @@ links_t to_links(const data_chunk& out,
188194
// Specialized threshold correlation.
189195
// O(n) over the sig set, ~100 bytes of stack, no heap.
190196
template <>
191-
links_t to_links<threshold::batch>(const data_chunk& out,
192-
const threshold::batch::span& in) NOEXCEPT
197+
links_t to_links<threshold::batch>(const stopper& cancel,
198+
const data_chunk& out, const threshold::batch::span& in) NOEXCEPT
193199
{
194200
BC_ASSERT(out.size() == in.size());
195201

@@ -200,6 +206,9 @@ links_t to_links<threshold::batch>(const data_chunk& out,
200206
links_t fails{};
201207
for (auto index = one; index <= in.size(); ++index)
202208
{
209+
if (cancel)
210+
return {};
211+
203212
// Find the start of the next group (or end).
204213
if ((index != in.size()) &&
205214
(in[index].id == in[group].id) &&
@@ -225,8 +234,8 @@ links_t to_links<threshold::batch>(const data_chunk& out,
225234
// Specialized multisig correlation.
226235
// O(n) over the sig set, ~100 bytes of stack, no heap.
227236
template <>
228-
links_t to_links<multisig::batch>(const data_chunk& out,
229-
const multisig::batch::span& in) NOEXCEPT
237+
links_t to_links<multisig::batch>(const stopper& cancel,
238+
const data_chunk& out, const multisig::batch::span& in) NOEXCEPT
230239
{
231240
BC_ASSERT(out.size() == in.size());
232241

@@ -237,6 +246,9 @@ links_t to_links<multisig::batch>(const data_chunk& out,
237246
links_t fails{};
238247
for (auto index = one; index <= in.size(); ++index)
239248
{
249+
if (cancel)
250+
return {};
251+
240252
// Find the start of the next group (or end).
241253
if ((index != in.size()) &&
242254
(in[index].id == in[group].id) &&
@@ -271,84 +283,84 @@ BC_POP_WARNING()
271283
// ----------------------------------------------------------------------------
272284
// static/protected
273285

274-
data_chunk schnorr::batch::evaluate(const schnorr::batch::span& batch,
275-
bool turbo) NOEXCEPT
286+
data_chunk schnorr::batch::evaluate(const stopper& cancel,
287+
const schnorr::batch::span& batch) NOEXCEPT
276288
{
277-
return batch_verify(batch, turbo);
289+
return batch_verify(cancel, batch);
278290
}
279291

280-
data_chunk threshold::batch::evaluate(const threshold::batch::span& batch,
281-
bool turbo) NOEXCEPT
292+
data_chunk threshold::batch::evaluate(const stopper& cancel,
293+
const threshold::batch::span& batch) NOEXCEPT
282294
{
283-
return batch_verify(batch, turbo);
295+
return batch_verify(cancel, batch);
284296
}
285297

286-
data_chunk ecdsa::batch::evaluate(const ecdsa::batch::span& batch,
287-
bool turbo) NOEXCEPT
298+
data_chunk ecdsa::batch::evaluate(const stopper& cancel,
299+
const ecdsa::batch::span& batch) NOEXCEPT
288300
{
289-
return batch_verify(batch, turbo);
301+
return batch_verify(cancel, batch);
290302
}
291303

292-
data_chunk multisig::batch::evaluate(const multisig::batch::span& batch,
293-
bool turbo) NOEXCEPT
304+
data_chunk multisig::batch::evaluate(const stopper& cancel,
305+
const multisig::batch::span& batch) NOEXCEPT
294306
{
295-
return batch_verify(batch, turbo);
307+
return batch_verify(cancel, batch);
296308
}
297309

298310
// correlate
299311
// ----------------------------------------------------------------------------
300312
// static/protected
301313

302-
links_t schnorr::batch::correlate(const data_chunk& out,
303-
const schnorr::batch::span& in) NOEXCEPT
314+
links_t schnorr::batch::correlate(const stopper& cancel,
315+
const data_chunk& out, const schnorr::batch::span& in) NOEXCEPT
304316
{
305-
return to_links(out, in);
317+
return to_links(cancel, out, in);
306318
}
307319

308-
links_t threshold::batch::correlate(const data_chunk& out,
309-
const threshold::batch::span& in) NOEXCEPT
320+
links_t threshold::batch::correlate(const stopper& cancel,
321+
const data_chunk& out, const threshold::batch::span& in) NOEXCEPT
310322
{
311-
return to_links(out, in);
323+
return to_links(cancel, out, in);
312324
}
313325

314-
links_t ecdsa::batch::correlate(const data_chunk& out,
315-
const ecdsa::batch::span& in) NOEXCEPT
326+
links_t ecdsa::batch::correlate(const stopper& cancel,
327+
const data_chunk& out, const ecdsa::batch::span& in) NOEXCEPT
316328
{
317-
return to_links(out, in);
329+
return to_links(cancel, out, in);
318330
}
319331

320-
links_t multisig::batch::correlate(const data_chunk& out,
321-
const multisig::batch::span& in) NOEXCEPT
332+
links_t multisig::batch::correlate(const stopper& cancel,
333+
const data_chunk& out, const multisig::batch::span& in) NOEXCEPT
322334
{
323-
return to_links(out, in);
335+
return to_links(cancel, out, in);
324336
}
325337

326338
// verify
327339
// ----------------------------------------------------------------------------
328340
// static/public
329341

330-
links_t schnorr::batch::verify(const schnorr::batch::span& batch,
331-
bool turbo) NOEXCEPT
342+
links_t schnorr::batch::verify(const stopper& cancel,
343+
const schnorr::batch::span& batch) NOEXCEPT
332344
{
333-
return correlate(evaluate(batch, turbo), batch);
345+
return correlate(cancel, evaluate(cancel, batch), batch);
334346
}
335347

336-
links_t threshold::batch::verify(const threshold::batch::span& batch,
337-
bool turbo) NOEXCEPT
348+
links_t threshold::batch::verify(const stopper& cancel,
349+
const threshold::batch::span& batch) NOEXCEPT
338350
{
339-
return correlate(evaluate(batch, turbo), batch);
351+
return correlate(cancel, evaluate(cancel, batch), batch);
340352
}
341353

342-
links_t ecdsa::batch::verify(const ecdsa::batch::span& batch,
343-
bool turbo) NOEXCEPT
354+
links_t ecdsa::batch::verify(const stopper& cancel,
355+
const ecdsa::batch::span& batch) NOEXCEPT
344356
{
345-
return correlate(evaluate(batch, turbo), batch);
357+
return correlate(cancel, evaluate(cancel, batch), batch);
346358
}
347359

348-
links_t multisig::batch::verify(const multisig::batch::span& batch,
349-
bool turbo) NOEXCEPT
360+
links_t multisig::batch::verify(const stopper& cancel,
361+
const multisig::batch::span& batch) NOEXCEPT
350362
{
351-
return correlate(evaluate(batch, turbo), batch);
363+
return correlate(cancel, evaluate(cancel, batch), batch);
352364
}
353365

354366
} // namespace system

test/crypto/secp256k1/batch.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ BOOST_AUTO_TEST_CASE(secp256k1__schnorr_batch_verify__all_valid__expected)
6161
batch{ hash, point3, sig3, { 2, 0, 0 } }
6262
};
6363

64-
const auto tokens = batch::verify({ triples.data(), triples.size() }, false);
64+
stopper cancel{};
65+
const auto tokens = batch::verify(cancel, { triples.data(), triples.size() });
6566
BOOST_REQUIRE(tokens.empty());
6667
}
6768

@@ -96,7 +97,8 @@ BOOST_AUTO_TEST_CASE(secp256k1__schnorr_batch_verify__one_invalid__expected)
9697
batch{ hash, point3, sig3, { 2, 0, 0 } }
9798
};
9899

99-
const auto tokens = batch::verify({ triples.data(), triples.size() }, false);
100+
stopper cancel{};
101+
const auto tokens = batch::verify(cancel, { triples.data(), triples.size() });
100102
BOOST_REQUIRE_EQUAL(tokens.size(), 1u);
101103
BOOST_REQUIRE_EQUAL(tokens.front(), from_little_array<batchy::link_t>(triples.at(1).id));
102104
}
@@ -126,7 +128,8 @@ BOOST_AUTO_TEST_CASE(secp256k1__ecdsa_batch_verify__all_valid__expected)
126128
batch{ hash, point3, sig3, { 2, 0, 0 } }
127129
};
128130

129-
const auto tokens = batch::verify({ triples.data(), triples.size() }, false);
131+
stopper cancel{};
132+
const auto tokens = batch::verify(cancel, { triples.data(), triples.size() });
130133
BOOST_REQUIRE(tokens.empty());
131134
}
132135

@@ -155,7 +158,8 @@ BOOST_AUTO_TEST_CASE(secp256k1__ecdsa_batch_verify__one_invalid__expected)
155158
batch{ hash, point3, sig3, { 2, 0, 0 } }
156159
};
157160

158-
const auto tokens = batch::verify({ triples.data(), triples.size() }, false);
161+
stopper cancel{};
162+
const auto tokens = batch::verify(cancel, { triples.data(), triples.size() });
159163
BOOST_REQUIRE_EQUAL(tokens.size(), 1u);
160164
BOOST_REQUIRE_EQUAL(tokens.front(), from_little_array<batchy::link_t>(triples.at(2).id));
161165
}
@@ -187,7 +191,8 @@ BOOST_AUTO_TEST_CASE(secp256k1__multisig_batch_verify__all_valid__expected)
187191
batch{ hash, point3, sig3, 0x20, 5, { 0, 0, 0 } } // (sig 2, key 0)
188192
};
189193

190-
const auto tokens = batch::verify({ triples.data(), triples.size() }, false);
194+
stopper cancel{};
195+
const auto tokens = batch::verify(cancel, { triples.data(), triples.size() });
191196
BOOST_REQUIRE(tokens.empty());
192197
}
193198

@@ -218,7 +223,8 @@ BOOST_AUTO_TEST_CASE(secp256k1__multisig_batch_verify__one_invalid__expected)
218223
batch{ hash, point3, sig3, 0x20, 7, { 0, 0, 0 } }
219224
};
220225

221-
const auto tokens = batch::verify({ triples.data(), triples.size() }, false);
226+
stopper cancel{};
227+
const auto tokens = batch::verify(cancel, { triples.data(), triples.size() });
222228
BOOST_REQUIRE_EQUAL(tokens.size(), 1u);
223229
BOOST_REQUIRE_EQUAL(tokens.front(), from_little_array<batchy::link_t>(triples.at(0).id));
224230
}

0 commit comments

Comments
 (0)