Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions include/bitcoin/database/impl/query/batch/schnorr.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ bool CLASS::purge_schnorr_signatures() NOEXCEPT

TEMPLATE
bool CLASS::set_signature(const hash_digest& digest, const ec_xonly& point,
const ec_signature& signature, uint16_t id,
const header_link& link) NOEXCEPT
const ec_signature& signature, const header_link& link) NOEXCEPT
{
using correlate_t = table::schnorr_correlate::put_ref;
using digest_t = table::schnorr_digest::put_ref;
Expand All @@ -97,15 +96,15 @@ bool CLASS::set_signature(const hash_digest& digest, const ec_xonly& point,

// Write one value to each column in corresponding positions.
return
store_.schnorr.correlate.put(fk, correlate_t{ {}, link, id }) &&
store_.schnorr.correlate.put(fk, correlate_t{ {}, link }) &&
store_.schnorr.digest.put(fk, digest_t{ {}, digest }) &&
store_.schnorr.xonly.put(fk, xonly_t{ {}, point }) &&
store_.schnorr.signature.put(fk, signature_t{ {}, signature });
// ========================================================================
}

TEMPLATE
bool CLASS::set_signatures(const threshold& batch, uint16_t id,
bool CLASS::set_signatures(const threshold& batch,
const header_link& link) NOEXCEPT
{
using correlate_t = table::schnorr_correlate::put_refs;
Expand All @@ -129,7 +128,7 @@ bool CLASS::set_signatures(const threshold& batch, uint16_t id,

// Write one value to each column in corresponding positions.
return
store_.schnorr.correlate.put(fk, correlate_t{ {}, batch, link, id }) &&
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 });
Expand Down
5 changes: 2 additions & 3 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -595,16 +595,15 @@ class query

/// Set single schnorr signature row.
bool set_signature(const hash_digest& digest, const ec_xonly& point,
const ec_signature& signature, uint16_t id,
const header_link& link) NOEXCEPT;
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, uint16_t id,
bool set_signatures(const threshold& batch,
const header_link& link) NOEXCEPT;

/// Invoke callback for each candidate match, false implies cancel.
Expand Down
48 changes: 3 additions & 45 deletions include/bitcoin/database/tables/caches/schnorr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ struct schnorr_correlate
: public no_map<schema::schnorr_correlate>
{
using hd = schema::header::link;
using category_t = system::chain::threshold::category_t;
using no_map<schema::schnorr_correlate>::nomap;

struct record
Expand All @@ -184,17 +183,11 @@ struct schnorr_correlate
inline bool from_data(reader& source) NOEXCEPT
{
header_fk = source.read_little_endian<hd::integer, hd::size>();
category = static_cast<category_t>(source.read_byte());
pair = source.read_little_endian<uint16_t>();
group = source.read_little_endian<uint16_t>();
BC_ASSERT(!source || source.get_read_position() == minrow);
return source;
}

hd::integer header_fk{};
category_t category{};
uint16_t pair{};
uint16_t group{};
};

struct put_ref
Expand All @@ -207,68 +200,33 @@ struct schnorr_correlate

inline bool to_data(flipper& sink) const NOEXCEPT
{
// 1 is required for single sig.
constexpr uint16_t pair = 1;
sink.write_little_endian<hd::integer, hd::size>(header_fk);
sink.write_byte(to_value(category_t::single));
sink.write_little_endian<uint16_t>(pair);
sink.write_little_endian<uint16_t>(group);
BC_ASSERT(!sink || sink.get_write_position() == minrow);
return sink;
}

const hd::integer header_fk{};
const uint16_t group{};
};

struct put_refs
: public schema::schnorr_correlate
{
inline link count() const NOEXCEPT
{
using namespace system;
return possible_narrow_cast<link::integer>(batch.tuples.size());
}

/// min in first row, max in second row (for within only).
inline uint16_t to_pair(size_t index, size_t count, bool between,
uint16_t min, uint16_t max) const NOEXCEPT
{
if (is_zero(index))
return min;

if (between && is_one(index) && count > one)
return max;

return {};
return system::possible_narrow_cast<link::integer>(rows);
}

inline bool to_data(flipper& sink) const NOEXCEPT
{
const auto rows = count();
const auto min = batch.minimum;
const auto max = batch.maximum;
const auto cat = batch.category;
const bool between = (cat == category_t::between);

for (size_t row{}; row < rows; ++row)
{
const auto category = is_zero(row) ? to_value(cat) : 0_u8;
const auto pair = to_pair(row, rows, between, min, max);

for (size_t row{}; row < count(); ++row)
sink.write_little_endian<hd::integer, hd::size>(header_fk);
sink.write_byte(category);
sink.write_little_endian<uint16_t>(pair);
sink.write_little_endian<uint16_t>(group);
}

BC_ASSERT(!sink || sink.get_write_position() == count() * minrow);
return sink;
}

const system::chain::threshold& batch;
const size_t rows{};
const hd::integer header_fk{};
const uint16_t group{};
};
};

Expand Down
2 changes: 1 addition & 1 deletion include/bitcoin/database/tables/schema.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ TABLE_COLUMN(ecdsa_correlate, one + count_ + schema::header::pk);
TABLE_COLUMN(schnorr_digest, system::hash_size);
TABLE_COLUMN(schnorr_xonly, system::ec_xonly_size);
TABLE_COLUMN(schnorr_signature, system::ec_signature_size);
TABLE_COLUMN(schnorr_correlate, one + two + count_ + schema::header::pk);
TABLE_COLUMN(schnorr_correlate, schema::header::pk);

// array
TABLE_COLUMN(silent_prefix, schema::prefix);
Expand Down
20 changes: 10 additions & 10 deletions test/query/batch/schnorr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__one_valid__em
const database::settings configuration{};
test::chunk_store store{ configuration };
test::query_accessor query{ store };
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 0, 42));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 42));

header_links links{};
BOOST_REQUIRE_EQUAL(query.schnorr_records(), 1u);
Expand All @@ -73,7 +73,7 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__one_invalid__
test::chunk_store store{ configuration };
test::query_accessor query{ store };
constexpr auto expected = 42u;
BOOST_REQUIRE(query.set_signature(sighash_bad, schnorr_xonly, schnorr_signature, 0, expected));
BOOST_REQUIRE(query.set_signature(sighash_bad, schnorr_xonly, schnorr_signature, expected));

header_links links{};
BOOST_REQUIRE_EQUAL(query.schnorr_records(), 1u);
Expand All @@ -90,14 +90,14 @@ BOOST_AUTO_TEST_CASE(query_batch_ecdsa__verify_schnorr_signatures__various__expe
constexpr auto expected1 = 42u;
constexpr auto expected2 = 24u;

BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 0, 1));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 0, 2));
BOOST_REQUIRE(query.set_signature(sighash_bad, schnorr_xonly, schnorr_signature, 0, expected1));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 0, 3));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 0, 4));
BOOST_REQUIRE(query.set_signature(sighash_bad, schnorr_xonly, schnorr_signature, 0, expected2));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 0, 5));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 0, 6));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 1));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 2));
BOOST_REQUIRE(query.set_signature(sighash_bad, schnorr_xonly, schnorr_signature, expected1));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 3));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 4));
BOOST_REQUIRE(query.set_signature(sighash_bad, schnorr_xonly, schnorr_signature, expected2));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 5));
BOOST_REQUIRE(query.set_signature(schnorr_sighash, schnorr_xonly, schnorr_signature, 6));

header_links links{};
BOOST_REQUIRE_EQUAL(query.schnorr_records(), 8u);
Expand Down
58 changes: 13 additions & 45 deletions test/tables/caches/schnorr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ using namespace system;
using namespace test;

// Shared test vectors.
constexpr auto group = 0x1234_u16;
constexpr auto header_fk = 0x00abcdef_u32;
constexpr ec_xonly xonly_a = base16_array
(
Expand Down Expand Up @@ -73,9 +72,7 @@ BOOST_AUTO_TEST_CASE(schnorr__create_verify_close__aggregate__expected)

// 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-first:
// header_fk(3) | category(1) | pair(2) | group(2). Single -> category=single,
// pair=1.
// 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;
Expand All @@ -94,10 +91,10 @@ BOOST_AUTO_TEST_CASE(schnorr__set_signature__single__expected)
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, group }));
BOOST_REQUIRE(instance.correlate.put(fk, correlate{ {}, header_fk }));

// Correlate: header_fk(3) | category=single(01) | pair=1 | group.
const auto expected_correlate = base16_chunk("efcdab" "01" "0100" "3412");
// Correlate: header_fk(3).
const auto expected_correlate = base16_chunk("efcdab");
const auto expected_digest = base16_chunk
(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
Expand Down Expand Up @@ -131,19 +128,14 @@ BOOST_AUTO_TEST_CASE(schnorr_correlate__put_ref__single__expected)
table::schnorr_correlate instance{ head_store, body_store };
BOOST_REQUIRE(instance.create());

// Single writes header_fk | category=single(01) | pair=1 | group.
const auto expected = base16_chunk("efcdab" "01" "0100" "3412");

BOOST_REQUIRE(instance.put(putter{ {}, header_fk, group }));
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
// ----------------------------------------------------------------------------

// A 3-tuple "between" threshold: category in row 0, min in row 0 pair, max in
// row 1 pair (op_within), remaining rows zero category/pair. Same group and
// header_fk on every row.
BOOST_AUTO_TEST_CASE(schnorr_correlate__put_refs__between__expected)
{
using putter = table::schnorr_correlate::put_refs;
Expand All @@ -153,33 +145,15 @@ BOOST_AUTO_TEST_CASE(schnorr_correlate__put_refs__between__expected)
table::schnorr_correlate instance{ head_store, body_store };
BOOST_REQUIRE(instance.create());

const ec_xonly point{};
const ec_signature sig{};
const chain::threshold batch
{
.tuples =
{
{ null_hash, point, sig },
{ null_hash, point, sig },
{ null_hash, point, sig }
},
.category = chain::threshold::category_t::between,
.minimum = 0x0002_u16,
.maximum = 0x0003_u16
};

// header_fk | category | pair | group, per row.
// row0: cat=between(08), pair=min(2); row1: cat=0, pair=max(3);
// row2: cat=0, pair=0. group/header_fk identical across rows.
const auto expected = base16_chunk
(
"efcdab" "08" "0200" "3412" // header_fk, between, min=2, group
"efcdab" "00" "0300" "3412" // header_fk, 0, max=3, group
"efcdab" "00" "0000" "3412" // header_fk, 0, 0, group
"efcdab"
"efcdab"
"efcdab"
);

// put_refs{ {}, batch, group, header_fk }.
BOOST_REQUIRE(instance.put(putter{ {}, batch, header_fk, group }));
// put_refs{ {}, size, header_fk }.
BOOST_REQUIRE(instance.put(putter{ {}, 3, header_fk }));
BOOST_REQUIRE_EQUAL(body_store.buffer(), expected);
}

Expand All @@ -188,8 +162,8 @@ BOOST_AUTO_TEST_CASE(schnorr_correlate__get__using_record__expected)
auto head = base16_chunk("02000000");
auto body = base16_chunk
(
"efcdab" "01" "0100" "3412" // header_fk, single, pair=1, group
"785634" "02" "0500" "7856" // header_fk, equal, pair=5, group
"efcdab"
"785634"
);

chunk_storage head_store{ head };
Expand All @@ -199,15 +173,9 @@ BOOST_AUTO_TEST_CASE(schnorr_correlate__get__using_record__expected)
table::schnorr_correlate::record out{};
BOOST_REQUIRE(instance.get(0u, out));
BOOST_REQUIRE(out.header_fk == header_fk);
BOOST_REQUIRE(out.category == chain::threshold::category_t::single);
BOOST_REQUIRE_EQUAL(out.pair, 0x0001_u16);
BOOST_REQUIRE_EQUAL(out.group, group);

BOOST_REQUIRE(instance.get(1u, out));
BOOST_REQUIRE(out.header_fk == 0x00345678_u32);
BOOST_REQUIRE(out.category == chain::threshold::category_t::equal);
BOOST_REQUIRE_EQUAL(out.pair, 0x0005_u16);
BOOST_REQUIRE_EQUAL(out.group, 0x5678_u16);
}

// schnorr_digest (single + multiple writers)
Expand Down
Loading