2626namespace libbitcoin {
2727namespace database {
2828namespace 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.
3154struct 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