Skip to content

Commit c745b8a

Browse files
authored
Merge pull request #838 from evoskuil/master
Implement and test SoA tables for ecdsa/schnorr/silent.
2 parents 2734ba8 + 374d90f commit c745b8a

6 files changed

Lines changed: 883 additions & 47 deletions

File tree

include/bitcoin/database/tables/caches/ecdsa.hpp

Lines changed: 203 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,31 @@
2626
namespace libbitcoin {
2727
namespace database {
2828
namespace table {
29+
30+
/// Utilities
31+
/// ---------------------------------------------------------------------------
32+
constexpr auto ecdsa_max = system::power2(to_half(byte_bits));
2933

30-
/// ecdsa is an array of ecdsa signature validation records.
34+
constexpr bool ecdsa_check(size_t m, size_t n) NOEXCEPT
35+
{
36+
return !is_zero(m) && !is_zero(n) && !(n > ecdsa_max) && !(m > n);
37+
}
38+
39+
constexpr size_t ecdsa_count(size_t m, size_t n) NOEXCEPT
40+
{
41+
using namespace system;
42+
const auto gap = n - m;
43+
if (is_subtract_overflow(n, m) || is_add_overflow(gap, one))
44+
return {};
45+
46+
const auto sum = add1(gap);
47+
if (is_multiply_overflow(m, sum))
48+
return {};
49+
50+
return m * sum;
51+
}
52+
53+
/// DEPRECATED: ecdsa is an array of ecdsa signature validation records.
3154
struct ecdsa
3255
: public no_map<schema::ecdsa>
3356
{
@@ -76,7 +99,6 @@ struct ecdsa
7699
&& header_fk == other.header_fk;
77100
}
78101

79-
/// pair: m (row 0, for all), n (row 1, for n > 1).
80102
system::hash_digest digest{};
81103
system::ec_compressed point{};
82104
system::ec_signature signature{};
@@ -110,8 +132,8 @@ struct ecdsa
110132
const system::hash_digest& digest;
111133
const system::ec_compressed& point;
112134
const system::ec_signature& signature;
113-
uint16_t group{};
114-
header::integer header_fk{};
135+
const uint16_t group{};
136+
const header::integer header_fk{};
115137
};
116138

117139
/// Writer for 1-of-1 multisig (0|0 packed in one row).
@@ -122,37 +144,26 @@ struct ecdsa
122144
// Terminal count fails the write attempt, so to_data() is guarded.
123145
inline link count() const NOEXCEPT
124146
{
125-
using namespace system;
126-
const auto m = sigs.size();
127-
const auto n = keys.size();
128-
const auto gap = n - m;
129-
if (is_subtract_overflow(n, m) || is_add_overflow(gap, one))
130-
return {};
131-
132-
const auto sum = add1(gap);
133-
if (is_multiply_overflow(m, sum))
134-
return {};
135-
136-
return possible_narrow_cast<link::integer>(m * sum);
147+
return system::possible_narrow_cast<link::integer>(
148+
ecdsa_count(sigs.size(), keys.size()));
137149
}
138150

139151
inline bool to_data(flipper& sink) const NOEXCEPT
140152
{
141-
using namespace system;
142-
constexpr auto max = power2(to_half(byte_bits));
143153
const auto m = sigs.size();
144154
const auto n = keys.size();
145-
if (is_zero(m) || is_zero(n) || n > max || m > n)
155+
if (!ecdsa_check(m, n))
146156
return false;
147157

158+
const auto gap = (n - m);
148159
for (size_t sig{}; sig < m; ++sig)
149160
{
150-
for (auto key = sig; key <= n - (m - sig); ++key)
161+
for (auto key = sig; key <= gap + sig; ++key)
151162
{
152163
sink.write_bytes(digest);
153164
sink.write_bytes(keys.at(key));
154165
sink.write_bytes(sigs.at(sig));
155-
sink.write_byte(pack_word<uint8_t>(sig, key));
166+
sink.write_byte(system::pack_word<uint8_t>(sig, key));
156167
sink.write_little_endian<uint16_t>(group);
157168
sink.write_little_endian<header::integer, header::size>(
158169
header_fk);
@@ -171,6 +182,177 @@ struct ecdsa
171182
};
172183
};
173184

185+
/// ecdsa_digest is an array of ecdsa verification record signature hashes.
186+
struct ecdsa_digest
187+
: public no_map<schema::ecdsa_digest>
188+
{
189+
using no_map<schema::ecdsa_digest>::nomap;
190+
191+
struct put_ref
192+
: public schema::ecdsa_digest
193+
{
194+
inline link count() const NOEXCEPT
195+
{
196+
return system::possible_narrow_cast<link::integer>(
197+
ecdsa_count(sigs, keys));
198+
}
199+
200+
inline bool to_data(flipper& sink) const NOEXCEPT
201+
{
202+
// ecdsa multisig capture is limited to common signature hash.
203+
for (size_t row{}; row < count(); ++row)
204+
sink.write_bytes(digest);
205+
206+
BC_ASSERT(!sink || sink.get_write_position() == count() * minrow);
207+
return sink;
208+
}
209+
210+
const size_t keys{};
211+
const size_t sigs{};
212+
const hash_digest& digest;
213+
};
214+
};
215+
216+
/// ecdsa_compressed is an array of ecdsa verification compressed public keys.
217+
struct ecdsa_compressed
218+
: public no_map<schema::ecdsa_compressed>
219+
{
220+
using no_map<schema::ecdsa_compressed>::nomap;
221+
222+
struct put_ref
223+
: public schema::ecdsa_compressed
224+
{
225+
inline link count() const NOEXCEPT
226+
{
227+
return system::possible_narrow_cast<link::integer>(
228+
ecdsa_count(sigs, keys.size()));
229+
}
230+
231+
inline bool to_data(flipper& sink) const NOEXCEPT
232+
{
233+
const auto m = sigs;
234+
const auto n = keys.size();
235+
if (!ecdsa_check(m, n))
236+
return false;
237+
238+
const auto gap = (n - m);
239+
for (size_t sig{}; sig < m; ++sig)
240+
for (auto key = sig; key <= gap + sig; ++key)
241+
sink.write_bytes(keys.at(key));
242+
243+
BC_ASSERT(!sink || sink.get_write_position() == count() * minrow);
244+
return sink;
245+
}
246+
247+
const system::ec_compresseds& keys;
248+
const size_t sigs{};
249+
};
250+
};
251+
252+
/// ecdsa_signature is an array of ecdsa verification signatures.
253+
struct ecdsa_signature
254+
: public no_map<schema::ecdsa_signature>
255+
{
256+
using no_map<schema::ecdsa_signature>::nomap;
257+
258+
struct put_ref
259+
: public schema::ecdsa_signature
260+
{
261+
inline link count() const NOEXCEPT
262+
{
263+
return system::possible_narrow_cast<link::integer>(
264+
ecdsa_count(sigs.size(), keys));
265+
}
266+
267+
inline bool to_data(flipper& sink) const NOEXCEPT
268+
{
269+
const auto m = sigs.size();
270+
const auto n = keys;
271+
if (!ecdsa_check(m, n))
272+
return false;
273+
274+
const auto gap = (n - m);
275+
for (size_t sig{}; sig < m; ++sig)
276+
for (auto key = sig; key <= gap + sig; ++key)
277+
sink.write_bytes(sigs.at(sig));
278+
279+
BC_ASSERT(!sink || sink.get_write_position() == count() * minrow);
280+
return sink;
281+
}
282+
283+
const size_t keys{};
284+
const system::ec_signatures& sigs;
285+
};
286+
};
287+
288+
/// ecdsa_correlate is an array of ecdsa correlation records.
289+
struct ecdsa_correlate
290+
: public no_map<schema::ecdsa_correlate>
291+
{
292+
using header = schema::header::link;
293+
using no_map<schema::ecdsa_correlate>::nomap;
294+
295+
struct record
296+
: public schema::ecdsa_correlate
297+
{
298+
inline link count() const NOEXCEPT
299+
{
300+
return 1;
301+
}
302+
303+
inline bool from_data(reader& source) NOEXCEPT
304+
{
305+
pair = source.read_byte();
306+
group = source.read_little_endian<uint16_t>();
307+
header_fk = source.read_little_endian<header::integer, header::size>();
308+
BC_ASSERT(!source || source.get_read_position() == minrow);
309+
return source;
310+
}
311+
312+
uint8_t pair{};
313+
uint16_t group{};
314+
header::integer header_fk{};
315+
};
316+
317+
struct put_ref
318+
: public schema::ecdsa_correlate
319+
{
320+
inline link count() const NOEXCEPT
321+
{
322+
return system::possible_narrow_cast<link::integer>(
323+
ecdsa_count(sigs, keys));
324+
}
325+
326+
inline bool to_data(flipper& sink) const NOEXCEPT
327+
{
328+
const auto m = sigs;
329+
const auto n = keys;
330+
if (!ecdsa_check(m, n))
331+
return false;
332+
333+
const auto gap = (n - m);
334+
for (size_t sig{}; sig < m; ++sig)
335+
{
336+
for (auto key = sig; key <= gap + sig; ++key)
337+
{
338+
sink.write_byte(system::pack_word<uint8_t>(sig, key));
339+
sink.write_little_endian<uint16_t>(group);
340+
sink.write_little_endian<header::integer, header::size>(
341+
header_fk);
342+
}
343+
}
344+
345+
BC_ASSERT(!sink || sink.get_write_position() == count() * minrow);
346+
return sink;
347+
}
348+
349+
const size_t keys{};
350+
const size_t sigs{};
351+
const uint16_t group{};
352+
const header::integer header_fk{};
353+
};
354+
};
355+
174356
} // namespace table
175357
} // namespace database
176358
} // namespace libbitcoin

0 commit comments

Comments
 (0)