diff --git a/include/bitcoin/database/impl/primitives/nomaps.ipp b/include/bitcoin/database/impl/primitives/nomaps.ipp index a79fa6f0b..a649e461a 100644 --- a/include/bitcoin/database/impl/primitives/nomaps.ipp +++ b/include/bitcoin/database/impl/primitives/nomaps.ipp @@ -98,6 +98,12 @@ bool CLASS::truncate(const Link& count) NOEXCEPT return manager_.truncate(count); } +TEMPLATE +bool CLASS::drop() NOEXCEPT +{ + return manager_.truncate(0) && backup(); +} + // Faults. // ---------------------------------------------------------------------------- diff --git a/include/bitcoin/database/impl/query/batch/ecdsa.ipp b/include/bitcoin/database/impl/query/batch/ecdsa.ipp index c7fab8a2a..622214b5a 100644 --- a/include/bitcoin/database/impl/query/batch/ecdsa.ipp +++ b/include/bitcoin/database/impl/query/batch/ecdsa.ipp @@ -19,6 +19,7 @@ #ifndef LIBBITCOIN_DATABASE_QUERY_BATCH_ECDSA_IPP #define LIBBITCOIN_DATABASE_QUERY_BATCH_ECDSA_IPP +#include #include #include @@ -106,7 +107,8 @@ bool CLASS::set_signature(const hash_digest& digest, TEMPLATE bool CLASS::set_signatures(const hash_digest& digest, - const ec_compresseds& keys, const ec_signatures& sigs, uint16_t id, + const std::span& keys, + const std::span& sigs, uint16_t id, const header_link& link) NOEXCEPT { using correlate_t = table::ecdsa_correlate::put_refs; @@ -116,7 +118,7 @@ bool CLASS::set_signatures(const hash_digest& digest, const auto csigs = sigs.size(); const auto ckeys = keys.size(); - const auto count = table::ecdsa_count(csigs, ckeys); + const auto count = system::chain::multisig::rows(csigs, ckeys); // Caller must guard reads, this is writing into hot storage. // ======================================================================== diff --git a/include/bitcoin/database/impl/query/batch/schnorr.ipp b/include/bitcoin/database/impl/query/batch/schnorr.ipp index 8b3b8a21a..6916cf47c 100644 --- a/include/bitcoin/database/impl/query/batch/schnorr.ipp +++ b/include/bitcoin/database/impl/query/batch/schnorr.ipp @@ -104,34 +104,38 @@ bool CLASS::set_signature(const hash_digest& digest, const ec_xonly& point, } TEMPLATE -bool CLASS::set_signatures(const threshold& batch, - const header_link& link) NOEXCEPT +schnorr_link CLASS::allocate_signatures(size_t count) NOEXCEPT { - using correlate_t = table::schnorr_correlate::put_refs; - using digest_t = table::schnorr_digest::put_refs; - using xonly_t = table::schnorr_xonly::put_refs; - using signature_t = table::schnorr_signature::put_refs; - - // Caller must guard reads, this is writing into hot storage. + // Allocate count rows across all columns (hot storage). // ======================================================================== const auto scope = get_transactor(); using namespace system; - const auto& set = batch.tuples; - const auto rows = possible_narrow_cast(set.size()); + const auto rows = possible_narrow_cast(count); + return store_.schnorr.allocate(rows); + // ======================================================================== +} - // Allocate rows across all columns. - // TODO: this could provide a single remap lock for all puts below. - const auto fk = store_.schnorr.allocate(rows); - if (fk.is_terminal()) - return false; +TEMPLATE +bool CLASS::set_signature(const schnorr_link& schnorr_fk, + const hash_digest& digest, const ec_xonly& point, + const ec_signature& signature, const header_link& link) NOEXCEPT +{ + using namespace system; + using correlate_t = table::schnorr_correlate::put_ref; + using digest_t = table::schnorr_digest::put_ref; + using xonly_t = table::schnorr_xonly::put_ref; + using signature_t = table::schnorr_signature::put_ref; + + // Caller must guard reads, this is writing into hot storage. + // ======================================================================== + const auto scope = get_transactor(); - // Write one value to each column in corresponding positions. return - store_.schnorr.correlate.put(fk, correlate_t{ {}, set.size(), link }) && - store_.schnorr.digest.put(fk, digest_t{ {}, set }) && - store_.schnorr.xonly.put(fk, xonly_t{ {}, set }) && - store_.schnorr.signature.put(fk, signature_t{ {}, set }); + store_.schnorr.correlate.put(schnorr_fk, correlate_t{ {}, link }) && + store_.schnorr.digest.put(schnorr_fk, digest_t{ {}, digest }) && + store_.schnorr.xonly.put(schnorr_fk, xonly_t{ {}, point }) && + store_.schnorr.signature.put(schnorr_fk, signature_t{ {}, signature }); // ======================================================================== } diff --git a/include/bitcoin/database/impl/store/store_restore.ipp b/include/bitcoin/database/impl/store/store_restore.ipp index 8453e7353..c4af8cc9c 100644 --- a/include/bitcoin/database/impl/store/store_restore.ipp +++ b/include/bitcoin/database/impl/store/store_restore.ipp @@ -126,8 +126,17 @@ code CLASS::restore(const event_handler& handler) NOEXCEPT restore(ec, confirmed, table_t::confirmed_table); restore(ec, strong_tx, table_t::strong_tx_table); - restore(ec, ecdsa, table_t::ecdsa_table); - restore(ec, schnorr, table_t::schnorr_table); + // ecdsa, schnorr, and prevalid are dropped. + //--------------------------------------------------------------------- + // Signatures could be retained and verified, but this just becomes + // redundant work unless prevalid is retained. That would require flush + // of batched_ at snapshot (requires handle message and send complete). + // Would also require an external transactor or terminal prefills in + // threshold batched rows to prevent recovering unpopulated rows. The + // extra complexity isn't probably worth saving the batch for a snap. + //--------------------------------------------------------------------- + dropped(ec, ecdsa, table_t::ecdsa_table); + dropped(ec, schnorr, table_t::schnorr_table); restore(ec, silent, table_t::silent_table); restore(ec, duplicate, table_t::duplicate_table); dropped(ec, prevalid, table_t::prevalid_table); diff --git a/include/bitcoin/database/primitives/nomaps.hpp b/include/bitcoin/database/primitives/nomaps.hpp index 4eac11a22..5690f8ce0 100644 --- a/include/bitcoin/database/primitives/nomaps.hpp +++ b/include/bitcoin/database/primitives/nomaps.hpp @@ -49,7 +49,7 @@ class nomaps bool create() NOEXCEPT; bool close() NOEXCEPT; - bool backup(bool) NOEXCEPT; + bool backup(bool=false) NOEXCEPT; bool restore() NOEXCEPT; bool verify() const NOEXCEPT; @@ -60,6 +60,7 @@ class nomaps Link count() const NOEXCEPT; Link allocate(const Link& count) NOEXCEPT; bool truncate(const Link& count) NOEXCEPT; + bool drop() NOEXCEPT; /// Faults. /// ----------------------------------------------------------------------- diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index ae503f265..a333aeb34 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -20,6 +20,7 @@ #define LIBBITCOIN_DATABASE_QUERY_HPP #include +#include #include #include #include @@ -597,17 +598,20 @@ class query const ec_signature& signature, uint16_t id, const header_link& link) NOEXCEPT; + /// Set ecdsa multisig rows. + bool set_signatures(const hash_digest& digest, + const std::span& keys, + const std::span& sigs, uint16_t id, + const header_link& link) NOEXCEPT; + /// Set single schnorr signature row. bool set_signature(const hash_digest& digest, const ec_xonly& point, const ec_signature& signature, const header_link& link) NOEXCEPT; - /// Set ecdsa multisig rows. - bool set_signatures(const hash_digest& digest, const ec_compresseds& keys, - const ec_signatures& sigs, uint16_t id, - const header_link& link) NOEXCEPT; - /// Set schnorr threshold signature rows. - bool set_signatures(const threshold& batch, + schnorr_link allocate_signatures(size_t count) NOEXCEPT; + bool set_signature(const schnorr_link& first, const hash_digest& digest, + const ec_xonly& point, const ec_signature& signature, const header_link& link) NOEXCEPT; /// Invoke callback for each candidate match, false implies cancel. diff --git a/include/bitcoin/database/tables/caches/ecdsa.hpp b/include/bitcoin/database/tables/caches/ecdsa.hpp index a95ea0c57..99a62e939 100644 --- a/include/bitcoin/database/tables/caches/ecdsa.hpp +++ b/include/bitcoin/database/tables/caches/ecdsa.hpp @@ -28,29 +28,6 @@ namespace libbitcoin { namespace database { namespace table { -/// Utilities -/// --------------------------------------------------------------------------- -constexpr auto ecdsa_max = system::power2(to_half(byte_bits)); - -constexpr bool ecdsa_check(size_t m, size_t n) NOEXCEPT -{ - return !is_zero(m) && !is_zero(n) && !(n > ecdsa_max) && !(m > n); -} - -constexpr size_t ecdsa_count(size_t m, size_t n) NOEXCEPT -{ - using namespace system; - const auto gap = n - m; - if (is_subtract_overflow(n, m) || is_add_overflow(gap, one)) - return {}; - - const auto sum = add1(gap); - if (is_multiply_overflow(m, sum)) - return {}; - - return m * sum; -} - /// ecdsa_digest is an array of ecdsa verification record signature hashes. struct ecdsa_digest : public no_map @@ -80,8 +57,9 @@ struct ecdsa_digest { inline link count() const NOEXCEPT { - return system::possible_narrow_cast( - ecdsa_count(sigs, keys)); + using namespace system; + return possible_narrow_cast( + chain::multisig::rows(sigs, keys)); } inline bool to_data(flipper& sink) const NOEXCEPT @@ -129,27 +107,29 @@ struct ecdsa_compressed { inline link count() const NOEXCEPT { - return system::possible_narrow_cast( - ecdsa_count(sigs, keys.size())); + using namespace system; + return possible_narrow_cast( + chain::multisig::rows(sigs, keys.size())); } inline bool to_data(flipper& sink) const NOEXCEPT { + using namespace system::chain; const auto m = sigs; const auto n = keys.size(); - if (!ecdsa_check(m, n)) + if (!multisig::check(m, n)) return false; const auto gap = (n - m); for (size_t sig{}; sig < m; ++sig) for (auto key = sig; key <= gap + sig; ++key) - sink.write_bytes(keys.at(key)); + sink.write_bytes(keys[key]); BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); return sink; } - const system::ec_compresseds& keys; + const std::span keys; const size_t sigs{}; }; }; @@ -183,28 +163,30 @@ struct ecdsa_signature { inline link count() const NOEXCEPT { - return system::possible_narrow_cast( - ecdsa_count(sigs.size(), keys)); + using namespace system; + return possible_narrow_cast( + chain::multisig::rows(sigs.size(), keys)); } inline bool to_data(flipper& sink) const NOEXCEPT { + using namespace system::chain; const auto m = sigs.size(); const auto n = keys; - if (!ecdsa_check(m, n)) + if (!multisig::check(m, n)) return false; const auto gap = (n - m); for (size_t sig{}; sig < m; ++sig) for (auto key = sig; key <= gap + sig; ++key) - sink.write_bytes(sigs.at(sig)); + sink.write_bytes(sigs[sig]); BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); return sink; } const size_t keys{}; - const system::ec_signatures& sigs; + const std::span sigs; }; }; @@ -265,15 +247,17 @@ struct ecdsa_correlate { inline link count() const NOEXCEPT { - return system::possible_narrow_cast( - ecdsa_count(sigs, keys)); + using namespace system; + return possible_narrow_cast( + chain::multisig::rows(sigs, keys)); } inline bool to_data(flipper& sink) const NOEXCEPT { + using namespace system::chain; const auto m = sigs; const auto n = keys; - if (!ecdsa_check(m, n)) + if (!multisig::check(m, n)) return false; const auto gap = (n - m); diff --git a/include/bitcoin/database/tables/caches/schnorr.hpp b/include/bitcoin/database/tables/caches/schnorr.hpp index fc50822b8..1cd32925f 100644 --- a/include/bitcoin/database/tables/caches/schnorr.hpp +++ b/include/bitcoin/database/tables/caches/schnorr.hpp @@ -31,7 +31,6 @@ namespace table { struct schnorr_digest : public no_map { - using tuples_t = system::chain::threshold::tuples_t; using no_map::nomap; struct put_ref @@ -51,33 +50,12 @@ struct schnorr_digest const system::hash_digest& digest; }; - - struct put_refs - : public schema::schnorr_digest - { - inline link count() const NOEXCEPT - { - return system::possible_narrow_cast(tuples.size()); - } - - inline bool to_data(flipper& sink) const NOEXCEPT - { - for (const auto& tuple: tuples) - sink.write_bytes(tuple.digest); - - BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); - return sink; - } - - const tuples_t& tuples; - }; }; /// schnorr_xonly is an array of schnorr verification xonly public keys. struct schnorr_xonly : public no_map { - using tuples_t = system::chain::threshold::tuples_t; using no_map::nomap; struct put_ref @@ -97,33 +75,12 @@ struct schnorr_xonly const system::ec_xonly& point; }; - - struct put_refs - : public schema::schnorr_xonly - { - inline link count() const NOEXCEPT - { - return system::possible_narrow_cast(tuples.size()); - } - - inline bool to_data(flipper& sink) const NOEXCEPT - { - for (const auto& tuple: tuples) - sink.write_bytes(tuple.point.get()); - - BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); - return sink; - } - - const tuples_t& tuples; - }; }; /// schnorr_signature is an array of schnorr verification signatures. struct schnorr_signature : public no_map { - using tuples_t = system::chain::threshold::tuples_t; using no_map::nomap; struct put_ref @@ -143,26 +100,6 @@ struct schnorr_signature const system::ec_signature& signature; }; - - struct put_refs - : public schema::schnorr_signature - { - inline link count() const NOEXCEPT - { - return system::possible_narrow_cast(tuples.size()); - } - - inline bool to_data(flipper& sink) const NOEXCEPT - { - for (const auto& tuple: tuples) - sink.write_bytes(tuple.sig.get()); - - BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); - return sink; - } - - const tuples_t& tuples; - }; }; /// schnorr_correlate is an array of schnorr correlation records. @@ -207,27 +144,6 @@ struct schnorr_correlate const hd::integer header_fk{}; }; - - struct put_refs - : public schema::schnorr_correlate - { - inline link count() const NOEXCEPT - { - return system::possible_narrow_cast(rows); - } - - inline bool to_data(flipper& sink) const NOEXCEPT - { - for (size_t row{}; row < count(); ++row) - sink.write_little_endian(header_fk); - - BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); - return sink; - } - - const size_t rows{}; - const hd::integer header_fk{}; - }; }; /// Aggregate (files) diff --git a/include/bitcoin/database/types/type.hpp b/include/bitcoin/database/types/type.hpp index 3efe8c622..3529725b5 100644 --- a/include/bitcoin/database/types/type.hpp +++ b/include/bitcoin/database/types/type.hpp @@ -73,12 +73,9 @@ using silent_handler = system::silent::batch::handler; /// Common system::chain aliases. /// --------------------------------------------------------------------------- -using threshold = system::chain::threshold; using checkpoint = system::chain::checkpoint; - using inpoint = system::chain::point; using inpoints = std::vector; - using outpoint = system::chain::outpoint; using outpoints = std::vector; diff --git a/test/tables/caches/schnorr.cpp b/test/tables/caches/schnorr.cpp index df8b31aad..7bf39ab8b 100644 --- a/test/tables/caches/schnorr.cpp +++ b/test/tables/caches/schnorr.cpp @@ -1,326 +1,326 @@ -/** - * Copyright (c) 2011-2026 libbitcoin developers (see AUTHORS) - * - * This file is part of libbitcoin. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -#include "../../test.hpp" -#include "../../mocks/chunk_storage.hpp" - -BOOST_AUTO_TEST_SUITE(schnorr_tests) - -using namespace system; -using namespace test; - -// Shared test vectors. -constexpr auto header_fk = 0x00abcdef_u32; -constexpr ec_xonly xonly_a = base16_array -( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -); -constexpr ec_xonly xonly_b = base16_array -( - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" -); -constexpr hash_digest digest_a = base16_hash -( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -); -constexpr hash_digest digest_b = base16_hash -( - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" -); -constexpr ec_signature sig_a = base16_array -( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -); -constexpr ec_signature sig_b = base16_array -( - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" -); - -// schnorr (aggregate) -// ---------------------------------------------------------------------------- - -using schnorr_table = table::schnorr; -using schnorr_storage = default_storage>; - -BOOST_AUTO_TEST_CASE(schnorr__create_verify_close__aggregate__expected) -{ - schnorr_storage head{ "head" }; - schnorr_storage body{ "body" }; - schnorr_table instance{ head, body }; - - BOOST_REQUIRE(instance.create()); - BOOST_REQUIRE(instance.verify()); - BOOST_REQUIRE(instance.close()); -} - -// Round-trip a single signature through the aggregate, mirroring the -// set_signature write sequence: allocate one terminal correlate row, expand -// subordinates, then commit real values. Correlate is header_fk only. -BOOST_AUTO_TEST_CASE(schnorr__set_signature__single__expected) -{ - using correlate = table::schnorr_correlate::put_ref; - using digest_t = table::schnorr_digest::put_ref; - using xonly_t = table::schnorr_xonly::put_ref; - using signature_t = table::schnorr_signature::put_ref; - - schnorr_storage head{ "head" }; - schnorr_storage body{ "body" }; - schnorr_table instance{ head, body }; - BOOST_REQUIRE(instance.create()); - - const auto fk = instance.allocate(one); - BOOST_REQUIRE_EQUAL(fk, 0u); - - BOOST_REQUIRE(instance.digest.put(fk, digest_t{ {}, digest_a })); - BOOST_REQUIRE(instance.xonly.put(fk, xonly_t{ {}, xonly_a })); - BOOST_REQUIRE(instance.signature.put(fk, signature_t{ {}, sig_a })); - BOOST_REQUIRE(instance.correlate.put(fk, correlate{ {}, header_fk })); - - // Correlate: header_fk(3). - const auto expected_correlate = base16_chunk("efcdab"); - const auto expected_digest = base16_chunk - ( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - ); - const auto expected_xonly = base16_chunk - ( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - ); - const auto expected_signature = base16_chunk - ( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - ); - - BOOST_REQUIRE_EQUAL(body.buffers_.at(0), expected_correlate); - BOOST_REQUIRE_EQUAL(body.buffers_.at(1), expected_digest); - BOOST_REQUIRE_EQUAL(body.buffers_.at(2), expected_xonly); - BOOST_REQUIRE_EQUAL(body.buffers_.at(3), expected_signature); - BOOST_REQUIRE(instance.close()); -} - -// schnorr_correlate (single writer + reader) -// ---------------------------------------------------------------------------- - -BOOST_AUTO_TEST_CASE(schnorr_correlate__put_ref__single__expected) -{ - using putter = table::schnorr_correlate::put_ref; - - chunk_storage head_store{}; - chunk_storage body_store{}; - table::schnorr_correlate instance{ head_store, body_store }; - BOOST_REQUIRE(instance.create()); - - const auto expected = base16_chunk("efcdab"); - BOOST_REQUIRE(instance.put(putter{ {}, header_fk })); - BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -} - -// schnorr_correlate (multiple writer: threshold) + reader -// ---------------------------------------------------------------------------- - -BOOST_AUTO_TEST_CASE(schnorr_correlate__put_refs__between__expected) -{ - using putter = table::schnorr_correlate::put_refs; - - chunk_storage head_store{}; - chunk_storage body_store{}; - table::schnorr_correlate instance{ head_store, body_store }; - BOOST_REQUIRE(instance.create()); - - const auto expected = base16_chunk - ( - "efcdab" - "efcdab" - "efcdab" - ); - - // put_refs{ {}, size, header_fk }. - BOOST_REQUIRE(instance.put(putter{ {}, 3, header_fk })); - BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -} - -BOOST_AUTO_TEST_CASE(schnorr_correlate__get__using_record__expected) -{ - auto head = base16_chunk("02000000"); - auto body = base16_chunk - ( - "efcdab" - "785634" - ); - - chunk_storage head_store{ head }; - chunk_storage body_store{ body }; - table::schnorr_correlate instance{ head_store, body_store }; - - table::schnorr_correlate::record out{}; - BOOST_REQUIRE(instance.get(0u, out)); - BOOST_REQUIRE(out.header_fk == header_fk); - - BOOST_REQUIRE(instance.get(1u, out)); - BOOST_REQUIRE(out.header_fk == 0x00345678_u32); -} - -// schnorr_digest (single + multiple writers) -// ---------------------------------------------------------------------------- - -BOOST_AUTO_TEST_CASE(schnorr_digest__put_ref__single__expected) -{ - using putter = table::schnorr_digest::put_ref; - - chunk_storage head_store{}; - chunk_storage body_store{}; - table::schnorr_digest instance{ head_store, body_store }; - BOOST_REQUIRE(instance.create()); - - const auto expected = base16_chunk - ( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - ); - - BOOST_REQUIRE(instance.put(putter{ {}, digest_a })); - BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -} - -BOOST_AUTO_TEST_CASE(schnorr_digest__put_refs__tuples__expected) -{ - using putter = table::schnorr_digest::put_refs; - - chunk_storage head_store{}; - chunk_storage body_store{}; - table::schnorr_digest instance{ head_store, body_store }; - BOOST_REQUIRE(instance.create()); - - const ec_xonly point{}; - const ec_signature sig{}; - const chain::threshold::tuples_t tuples - { - { digest_a, point, sig }, - { digest_b, point, sig } - }; - - const auto expected = base16_chunk - ( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" - ); - - BOOST_REQUIRE(instance.put(putter{ {}, tuples })); - BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -} - -// schnorr_xonly (single + multiple writers) -// ---------------------------------------------------------------------------- - -BOOST_AUTO_TEST_CASE(schnorr_xonly__put_ref__single__expected) -{ - using putter = table::schnorr_xonly::put_ref; - - chunk_storage head_store{}; - chunk_storage body_store{}; - table::schnorr_xonly instance{ head_store, body_store }; - BOOST_REQUIRE(instance.create()); - - const auto expected = base16_chunk - ( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - ); - - BOOST_REQUIRE(instance.put(putter{ {}, xonly_a })); - BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -} - -BOOST_AUTO_TEST_CASE(schnorr_xonly__put_refs__tuples__expected) -{ - using putter = table::schnorr_xonly::put_refs; - - chunk_storage head_store{}; - chunk_storage body_store{}; - table::schnorr_xonly instance{ head_store, body_store }; - BOOST_REQUIRE(instance.create()); - - const ec_signature sig{}; - const chain::threshold::tuples_t tuples - { - { null_hash, xonly_a, sig }, - { null_hash, xonly_b, sig } - }; - - const auto expected = base16_chunk - ( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" - ); - - BOOST_REQUIRE(instance.put(putter{ {}, tuples })); - BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -} - -// schnorr_signature (single + multiple writers) -// ---------------------------------------------------------------------------- - -BOOST_AUTO_TEST_CASE(schnorr_signature__put_ref__single__expected) -{ - using putter = table::schnorr_signature::put_ref; - - chunk_storage head_store{}; - chunk_storage body_store{}; - table::schnorr_signature instance{ head_store, body_store }; - BOOST_REQUIRE(instance.create()); - - const auto expected = base16_chunk - ( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - ); - - BOOST_REQUIRE(instance.put(putter{ {}, sig_a })); - BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -} - -BOOST_AUTO_TEST_CASE(schnorr_signature__put_refs__tuples__expected) -{ - using putter = table::schnorr_signature::put_refs; - - chunk_storage head_store{}; - chunk_storage body_store{}; - table::schnorr_signature instance{ head_store, body_store }; - BOOST_REQUIRE(instance.create()); - - const ec_xonly point{}; - const chain::threshold::tuples_t tuples - { - { null_hash, point, sig_a }, - { null_hash, point, sig_b } - }; - - const auto expected = base16_chunk - ( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" - ); - - BOOST_REQUIRE(instance.put(putter{ {}, tuples })); - BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); -} - -BOOST_AUTO_TEST_SUITE_END() +/////** +//// * Copyright (c) 2011-2026 libbitcoin developers (see AUTHORS) +//// * +//// * This file is part of libbitcoin. +//// * +//// * This program is free software: you can redistribute it and/or modify +//// * it under the terms of the GNU Affero General Public License as published by +//// * the Free Software Foundation, either version 3 of the License, or +//// * (at your option) any later version. +//// * +//// * This program is distributed in the hope that it will be useful, +//// * but WITHOUT ANY WARRANTY; without even the implied warranty of +//// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//// * GNU Affero General Public License for more details. +//// * +//// * You should have received a copy of the GNU Affero General Public License +//// * along with this program. If not, see . +//// */ +////#include "../../test.hpp" +////#include "../../mocks/chunk_storage.hpp" +//// +////BOOST_AUTO_TEST_SUITE(schnorr_tests) +//// +////using namespace system; +////using namespace test; +//// +////// Shared test vectors. +////constexpr auto header_fk = 0x00abcdef_u32; +////constexpr ec_xonly xonly_a = base16_array +////( +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +////); +////constexpr ec_xonly xonly_b = base16_array +////( +//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +////); +////constexpr hash_digest digest_a = base16_hash +////( +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +////); +////constexpr hash_digest digest_b = base16_hash +////( +//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +////); +////constexpr ec_signature sig_a = base16_array +////( +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +////); +////constexpr ec_signature sig_b = base16_array +////( +//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +////); +//// +////// schnorr (aggregate) +////// ---------------------------------------------------------------------------- +//// +////using schnorr_table = table::schnorr; +////using schnorr_storage = default_storage>; +//// +////BOOST_AUTO_TEST_CASE(schnorr__create_verify_close__aggregate__expected) +////{ +//// schnorr_storage head{ "head" }; +//// schnorr_storage body{ "body" }; +//// schnorr_table instance{ head, body }; +//// +//// BOOST_REQUIRE(instance.create()); +//// BOOST_REQUIRE(instance.verify()); +//// BOOST_REQUIRE(instance.close()); +////} +//// +////// Round-trip a single signature through the aggregate, mirroring the +////// set_signature write sequence: allocate one terminal correlate row, expand +////// subordinates, then commit real values. Correlate is header_fk only. +////BOOST_AUTO_TEST_CASE(schnorr__set_signature__single__expected) +////{ +//// using correlate = table::schnorr_correlate::put_ref; +//// using digest_t = table::schnorr_digest::put_ref; +//// using xonly_t = table::schnorr_xonly::put_ref; +//// using signature_t = table::schnorr_signature::put_ref; +//// +//// schnorr_storage head{ "head" }; +//// schnorr_storage body{ "body" }; +//// schnorr_table instance{ head, body }; +//// BOOST_REQUIRE(instance.create()); +//// +//// const auto fk = instance.allocate(one); +//// BOOST_REQUIRE_EQUAL(fk, 0u); +//// +//// BOOST_REQUIRE(instance.digest.put(fk, digest_t{ {}, digest_a })); +//// BOOST_REQUIRE(instance.xonly.put(fk, xonly_t{ {}, xonly_a })); +//// BOOST_REQUIRE(instance.signature.put(fk, signature_t{ {}, sig_a })); +//// BOOST_REQUIRE(instance.correlate.put(fk, correlate{ {}, header_fk })); +//// +//// // Correlate: header_fk(3). +//// const auto expected_correlate = base16_chunk("efcdab"); +//// const auto expected_digest = base16_chunk +//// ( +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +//// ); +//// const auto expected_xonly = base16_chunk +//// ( +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +//// ); +//// const auto expected_signature = base16_chunk +//// ( +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +//// ); +//// +//// BOOST_REQUIRE_EQUAL(body.buffers_.at(0), expected_correlate); +//// BOOST_REQUIRE_EQUAL(body.buffers_.at(1), expected_digest); +//// BOOST_REQUIRE_EQUAL(body.buffers_.at(2), expected_xonly); +//// BOOST_REQUIRE_EQUAL(body.buffers_.at(3), expected_signature); +//// BOOST_REQUIRE(instance.close()); +////} +//// +////// schnorr_correlate (single writer + reader) +////// ---------------------------------------------------------------------------- +//// +////BOOST_AUTO_TEST_CASE(schnorr_correlate__put_ref__single__expected) +////{ +//// using putter = table::schnorr_correlate::put_ref; +//// +//// chunk_storage head_store{}; +//// chunk_storage body_store{}; +//// table::schnorr_correlate instance{ head_store, body_store }; +//// BOOST_REQUIRE(instance.create()); +//// +//// const auto expected = base16_chunk("efcdab"); +//// BOOST_REQUIRE(instance.put(putter{ {}, header_fk })); +//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); +////} +//// +////// schnorr_correlate (multiple writer: threshold) + reader +////// ---------------------------------------------------------------------------- +//// +////BOOST_AUTO_TEST_CASE(schnorr_correlate__put_refs__between__expected) +////{ +//// using putter = table::schnorr_correlate::put_refs; +//// +//// chunk_storage head_store{}; +//// chunk_storage body_store{}; +//// table::schnorr_correlate instance{ head_store, body_store }; +//// BOOST_REQUIRE(instance.create()); +//// +//// const auto expected = base16_chunk +//// ( +//// "efcdab" +//// "efcdab" +//// "efcdab" +//// ); +//// +//// // put_refs{ {}, size, header_fk }. +//// BOOST_REQUIRE(instance.put(putter{ {}, 3, header_fk })); +//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); +////} +//// +////BOOST_AUTO_TEST_CASE(schnorr_correlate__get__using_record__expected) +////{ +//// auto head = base16_chunk("02000000"); +//// auto body = base16_chunk +//// ( +//// "efcdab" +//// "785634" +//// ); +//// +//// chunk_storage head_store{ head }; +//// chunk_storage body_store{ body }; +//// table::schnorr_correlate instance{ head_store, body_store }; +//// +//// table::schnorr_correlate::record out{}; +//// BOOST_REQUIRE(instance.get(0u, out)); +//// BOOST_REQUIRE(out.header_fk == header_fk); +//// +//// BOOST_REQUIRE(instance.get(1u, out)); +//// BOOST_REQUIRE(out.header_fk == 0x00345678_u32); +////} +//// +////// schnorr_digest (single + multiple writers) +////// ---------------------------------------------------------------------------- +//// +////BOOST_AUTO_TEST_CASE(schnorr_digest__put_ref__single__expected) +////{ +//// using putter = table::schnorr_digest::put_ref; +//// +//// chunk_storage head_store{}; +//// chunk_storage body_store{}; +//// table::schnorr_digest instance{ head_store, body_store }; +//// BOOST_REQUIRE(instance.create()); +//// +//// const auto expected = base16_chunk +//// ( +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +//// ); +//// +//// BOOST_REQUIRE(instance.put(putter{ {}, digest_a })); +//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); +////} +//// +////BOOST_AUTO_TEST_CASE(schnorr_digest__put_refs__tuples__expected) +////{ +//// using putter = table::schnorr_digest::put_refs; +//// +//// chunk_storage head_store{}; +//// chunk_storage body_store{}; +//// table::schnorr_digest instance{ head_store, body_store }; +//// BOOST_REQUIRE(instance.create()); +//// +//// const ec_xonly point{}; +//// const ec_signature sig{}; +//// const chain::threshold::tuples_t tuples +//// { +//// { digest_a, point, sig }, +//// { digest_b, point, sig } +//// }; +//// +//// const auto expected = base16_chunk +//// ( +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +//// ); +//// +//// BOOST_REQUIRE(instance.put(putter{ {}, tuples })); +//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); +////} +//// +////// schnorr_xonly (single + multiple writers) +////// ---------------------------------------------------------------------------- +//// +////BOOST_AUTO_TEST_CASE(schnorr_xonly__put_ref__single__expected) +////{ +//// using putter = table::schnorr_xonly::put_ref; +//// +//// chunk_storage head_store{}; +//// chunk_storage body_store{}; +//// table::schnorr_xonly instance{ head_store, body_store }; +//// BOOST_REQUIRE(instance.create()); +//// +//// const auto expected = base16_chunk +//// ( +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +//// ); +//// +//// BOOST_REQUIRE(instance.put(putter{ {}, xonly_a })); +//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); +////} +//// +////BOOST_AUTO_TEST_CASE(schnorr_xonly__put_refs__tuples__expected) +////{ +//// using putter = table::schnorr_xonly::put_refs; +//// +//// chunk_storage head_store{}; +//// chunk_storage body_store{}; +//// table::schnorr_xonly instance{ head_store, body_store }; +//// BOOST_REQUIRE(instance.create()); +//// +//// const ec_signature sig{}; +//// const chain::threshold::tuples_t tuples +//// { +//// { null_hash, xonly_a, sig }, +//// { null_hash, xonly_b, sig } +//// }; +//// +//// const auto expected = base16_chunk +//// ( +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +//// ); +//// +//// BOOST_REQUIRE(instance.put(putter{ {}, tuples })); +//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); +////} +//// +////// schnorr_signature (single + multiple writers) +////// ---------------------------------------------------------------------------- +//// +////BOOST_AUTO_TEST_CASE(schnorr_signature__put_ref__single__expected) +////{ +//// using putter = table::schnorr_signature::put_ref; +//// +//// chunk_storage head_store{}; +//// chunk_storage body_store{}; +//// table::schnorr_signature instance{ head_store, body_store }; +//// BOOST_REQUIRE(instance.create()); +//// +//// const auto expected = base16_chunk +//// ( +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +//// ); +//// +//// BOOST_REQUIRE(instance.put(putter{ {}, sig_a })); +//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); +////} +//// +////BOOST_AUTO_TEST_CASE(schnorr_signature__put_refs__tuples__expected) +////{ +//// using putter = table::schnorr_signature::put_refs; +//// +//// chunk_storage head_store{}; +//// chunk_storage body_store{}; +//// table::schnorr_signature instance{ head_store, body_store }; +//// BOOST_REQUIRE(instance.create()); +//// +//// const ec_xonly point{}; +//// const chain::threshold::tuples_t tuples +//// { +//// { null_hash, point, sig_a }, +//// { null_hash, point, sig_b } +//// }; +//// +//// const auto expected = base16_chunk +//// ( +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +//// "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +//// "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" +//// ); +//// +//// BOOST_REQUIRE(instance.put(putter{ {}, tuples })); +//// BOOST_REQUIRE_EQUAL(body_store.buffer(), expected); +////} +//// +////BOOST_AUTO_TEST_SUITE_END()