Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assignment verification #2389

Merged
merged 33 commits into from
Mar 17, 2025
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
7846f23
Additional checks
kamilsa Feb 5, 2025
0bda44b
Update kagome crates
kamilsa Feb 26, 2025
5b08b0d
Merge remote-tracking branch 'origin/master' into feature/assignment-…
kamilsa Feb 26, 2025
3f62b08
Update transcript to use with vectors
kamilsa Feb 27, 2025
12f9783
Add RelayVRFModuloCompact check
kamilsa Feb 27, 2025
8d8e3df
bad_vrf_test (broken so far)
kamilsa Feb 28, 2025
2ab89ae
bad_vrf_test (passes)
kamilsa Mar 2, 2025
c131663
check_rejects_modulo_sample_out_of_bounds passes
kamilsa Mar 4, 2025
018860d
Move check_mutated_assignments out of test bodies
kamilsa Mar 4, 2025
866fd45
Add n_validators, n_cores, rotation_offset args to check_mutated_assi…
kamilsa Mar 4, 2025
b9de352
Add check_rejects_delay_claimed_core_wrong
kamilsa Mar 4, 2025
9efcec8
Add check_rejects_modulo_core_wrong
kamilsa Mar 4, 2025
b30ff0e
Add check_rejects_delay_bad_vrf
kamilsa Mar 4, 2025
5f3354f
Self-review
kamilsa Mar 4, 2025
eb63804
Merge branch 'master' into feature/assignment-verification
kamilsa Mar 4, 2025
41e76a9
Suppress some clang-tidy issues
kamilsa Mar 4, 2025
6f82ee0
Merge remote-tracking branch 'origin/feature/assignment-verification'…
kamilsa Mar 4, 2025
dac0557
Review
kamilsa Mar 4, 2025
fc8d631
Review comment
kamilsa Mar 5, 2025
560bc0f
Fix ASAN
kamilsa Mar 5, 2025
3f43305
Clang-tidy fixes
kamilsa Mar 5, 2025
666ed14
Clear cores in all cases
kamilsa Mar 6, 2025
6f9d36a
Merge branch 'master' into feature/assignment-verification
kamilsa Mar 6, 2025
603f7e4
Merge remote-tracking branch 'origin/master' into feature/assignment-…
kamilsa Mar 10, 2025
c2eaec8
Fixes
kamilsa Mar 11, 2025
482eec6
Make append message receive template int arg
kamilsa Mar 13, 2025
c7d6e66
VrfVerifyExtra test
kamilsa Mar 13, 2025
f0e8b66
Merge remote-tracking branch 'origin/master' into feature/assignment-…
kamilsa Mar 13, 2025
d9583f7
Merge fixes
kamilsa Mar 13, 2025
8498215
More merge fixes
kamilsa Mar 13, 2025
24c798c
Merge branch 'master' into feature/assignment-verification
kamilsa Mar 13, 2025
e1f1ed5
Merge branch 'master' into feature/assignment-verification
kamilsa Mar 14, 2025
7c2eaaa
Merge branch 'master' into feature/assignment-verification
kamilsa Mar 14, 2025
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
4 changes: 2 additions & 2 deletions cmake/Hunter/config.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ endif ()

hunter_config(
kagome-crates
URL https://github.com/qdrvm/kagome-crates/archive/refs/tags/v1.0.4.tar.gz
SHA1 a85f3ca7a5dac2d22c609cc0c3f39408ad72dba8
URL https://github.com/qdrvm/kagome-crates/archive/11fd7ec3337b631fdf08188d76851352bf15d78a.tar.gz
SHA1 f38ad7bf5609ae981bb2eaf14b6372a7674083e7
)

hunter_config(
Expand Down
207 changes: 183 additions & 24 deletions core/parachain/approval/approval_distribution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@
#include "network/router.hpp"
#include "parachain/approval/approval.hpp"
#include "parachain/approval/approval_distribution.hpp"

#include "parachain/approval/approval_distribution_error.hpp"
#include "parachain/approval/approval_thread_pool.hpp"
#include "parachain/approval/state.hpp"
#include "parachain/pvf/pvf.hpp"
#include "parachain/validator/parachain_processor.hpp"
#include "primitives/math.hpp"
#include "primitives/transcript.hpp"
#include "runtime/runtime_api/parachain_host_types.hpp"
#include "utils/map.hpp"
#include "utils/pool_handler_ready_make.hpp"
Expand Down Expand Up @@ -453,13 +455,83 @@ namespace {
UNREACHABLE;
}

outcome::result<kagome::network::DelayTranche> checkAssignmentCert(
// // Implement the assigned_core_transcript function
kagome::primitives::Transcript assigned_core_transcript(
const kagome::parachain::CoreIndex &core_index) {
kagome::primitives::Transcript t;
t.initialize({'A',
'&',
'V',
' ',
'A',
'S',
'S',
'I',
'G',
'N',
'E',
'D',
' ',
'v',
'2'});
t.append_message("core", core_index);

return {t};
}

kagome::primitives::Transcript assigned_cores_transcript(
const scale::BitVec &core_indices) {
kagome::primitives::Transcript t;
t.initialize({'A',
'&',
'V',
' ',
'A',
'S',
'S',
'I',
'G',
'N',
'E',
'D',
' ',
'v',
'2'});
t.append_message({'c', 'o', 'r', 'e', 's'},
scale::encode(core_indices).value());
return {t};
}

kagome::primitives::Transcript relay_vrf_modulo_transcript_v1(
const RelayVRFStory &relay_vrf_story, uint32_t sample) {
kagome::primitives::Transcript transcript;
transcript.initialize({'A', '&', 'V', ' ', 'M', 'O', 'D'});
transcript.append_message({'R', 'C', '-', 'V', 'R', 'F'},
relay_vrf_story.data);
transcript.append_message({'s', 'a', 'm', 'p', 'l', 'e'}, sample);
return {transcript};
}

kagome::primitives::Transcript relay_vrf_modulo_transcript_v2(
const RelayVRFStory &relay_vrf_story) {
kagome::primitives::Transcript transcript;
transcript.initialize({'A', '&', 'V', ' ', 'M', 'O', 'D', ' ', 'v', '2'});
transcript.append_message({'R', 'C', '-', 'V', 'R', 'F'},
relay_vrf_story.data);
return {transcript};
}

} // namespace

namespace kagome::parachain {

outcome::result<DelayTranche> checkAssignmentCert(
const scale::BitVec &claimed_core_indices,
kagome::network::ValidatorIndex validator_index,
const kagome::runtime::SessionInfo &config,
ValidatorIndex validator_index,
const runtime::SessionInfo &config,
const RelayVRFStory &relay_vrf_story,
const kagome::parachain::approval::AssignmentCertV2 &assignment,
const std::vector<kagome::network::GroupIndex> &backing_groups) {
const approval::AssignmentCertV2 &assignment,
const std::vector<GroupIndex> &backing_groups) {
using namespace kagome; // NOLINT(google-build-using-namespace)
using parachain::ApprovalDistributionError;

Expand All @@ -468,10 +540,9 @@ namespace {
}

const auto &validator_public = config.assignment_keys[validator_index];
// OUTCOME_TRY(pk, network::ValidatorId::fromSpan(validator_public));

if (kagome::parachain::approval::count_ones(claimed_core_indices) == 0
|| kagome::parachain::approval::count_ones(claimed_core_indices)
if (approval::count_ones(claimed_core_indices) == 0
|| approval::count_ones(claimed_core_indices)
!= backing_groups.size()) {
return ApprovalDistributionError::CORE_INDEX_OUT_OF_BOUNDS;
}
Expand Down Expand Up @@ -511,29 +582,120 @@ namespace {

return visit_in_place(
assignment.kind,
[&](const parachain::approval::RelayVRFModuloCompact &obj)
-> outcome::result<kagome::network::DelayTranche> {
[&](const approval::RelayVRFModuloCompact &obj)
-> outcome::result<DelayTranche> {
const auto core_bitfield = obj.core_bitfield;
if (claimed_core_indices != core_bitfield) {
return ApprovalDistributionError::VRF_MODULO_CORE_INDEX_MISMATCH;
}

/// TODO(iceseer): `vrf_verify_extra` check
/// TODO(iceseer): `relay_vrf_modulo_core`
return network::DelayTranche(0ull);
auto log_ =
kagome::log::createLogger("ApprovalDistribution", "parachain");

primitives::Transcript modulo_transcript =
relay_vrf_modulo_transcript_v2(relay_vrf_story);
primitives::Transcript transcript =
assigned_cores_transcript(obj.core_bitfield);

auto res = sr25519_vrf_verify_extra(
validator_public.data(),
assignment.vrf.output.data(),
vrf_proof.data(),
reinterpret_cast<const Strobe128 *>(
modulo_transcript.data().data()),
reinterpret_cast<const Strobe128 *>(transcript.data().data()));

// Prepare output variables
uint32_t *cores_out = nullptr;
size_t cores_out_sz = 0;

sr25519_relay_vrf_modulo_cores(&res.input_bytes,
&res.output_bytes,
config.relay_vrf_modulo_samples,
config.n_cores,
&cores_out,
&cores_out_sz);
std::vector<uint32_t> resulting_cores;
resulting_cores.reserve(cores_out_sz);
for (size_t ix = 0; ix < cores_out_sz; ++ix) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
const auto ci = cores_out[ix];
resulting_cores.push_back(ci);
}

// Validate that all claimed cores are in the resulting cores
bool all_cores_valid = true;
for (size_t claimed_core_index = 0;
claimed_core_index < claimed_core_indices.bits.size();
++claimed_core_index) {
if (claimed_core_indices.bits[claimed_core_index]) {
if (std::ranges::find(resulting_cores, claimed_core_index)
== resulting_cores.end()) {
all_cores_valid = false;

SL_DEBUG(
log_,
"Assignment claimed cores mismatch. (resulting_cores={}, "
"claimed_core_indices={}, claimed_core_index={})",
fmt::join(resulting_cores, ","),
fmt::join(claimed_core_indices.bits, ","),
claimed_core_index);

break;
}
}
}

if (!all_cores_valid) {
// Clean up allocated memory
if (cores_out) {
sr25519_clear_assigned_cores_v2(cores_out, cores_out_sz);
}
return ApprovalDistributionError::VRF_MODULO_CORE_INDEX_MISMATCH;
}

return DelayTranche(0ull);
},
[&](const parachain::approval::RelayVRFModulo &obj)
-> outcome::result<kagome::network::DelayTranche> {
[&](const approval::RelayVRFModulo &obj)
-> outcome::result<DelayTranche> {
const auto sample = obj.sample;
if (sample >= config.relay_vrf_modulo_samples) {
return ApprovalDistributionError::SAMPLE_OUT_OF_BOUNDS;
}
/// TODO(iceseer): `vrf_verify_extra` check
/// TODO(iceseer): `relay_vrf_modulo_core`
return network::DelayTranche(0ull);

auto log_ =
kagome::log::createLogger("ApprovalDistribution", "parachain");
if (parachain::approval::count_ones(claimed_core_indices) != 1) {
SL_WARN(log_,
"`RelayVRFModulo` assignment must always claim 1 core.");
return ApprovalDistributionError::INVALID_ARGUMENTS;
}
primitives::Transcript modulo_transcript =
relay_vrf_modulo_transcript_v1(relay_vrf_story, sample);
primitives::Transcript transcript =
assigned_core_transcript(first_claimed_core_index);
auto res = sr25519_vrf_verify_extra(
validator_public.data(),
assignment.vrf.output.data(),
vrf_proof.data(),
reinterpret_cast<const Strobe128 *>(
modulo_transcript.data().data()),
reinterpret_cast<const Strobe128 *>(transcript.data().data()));

auto core = sr25519_relay_vrf_modulo_core(
&res.input_bytes, &res.output_bytes, config.n_cores);

if (core == first_claimed_core_index) {
return DelayTranche(0ull);
}
SL_DEBUG(log_,
"VRF modulo core mismatch: expected {}, got {}",
first_claimed_core_index,
core);
return ApprovalDistributionError::VRF_MODULO_CORE_INDEX_MISMATCH;
},
[&](const parachain::approval::RelayVRFDelay &obj)
-> outcome::result<kagome::network::DelayTranche> {
[&](const approval::RelayVRFDelay &obj)
-> outcome::result<DelayTranche> {
const auto core_index = obj.core_index;
if (parachain::approval::count_ones(claimed_core_indices) != 1) {
return ApprovalDistributionError::INVALID_ARGUMENTS;
Expand All @@ -544,7 +706,7 @@ namespace {
}

// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
network::DelayTranche tranche;
DelayTranche tranche;
if (SR25519_SIGNATURE_RESULT_OK
!= sr25519_vrf_verify_and_get_tranche(
validator_public.data(),
Expand All @@ -561,9 +723,6 @@ namespace {
});
}

} // namespace

namespace kagome::parachain {
constexpr auto kMetricNoShowsTotal =
"kagome_parachain_approvals_no_shows_total";

Expand Down
22 changes: 22 additions & 0 deletions core/parachain/approval/approval_distribution.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,28 @@
#include "runtime/runtime_api/parachain_host_types.hpp"
#include "utils/safe_object.hpp"

namespace kagome::parachain {
/**
* @brief Checks if an assignment certificate is valid and returns the
* corresponding delay tranche
* @param claimed_core_indices Bitfield of the core indices being claimed
* @param validator_index Index of the validator making the assignment
* @param session_info Current session info containing validator and
* assignment keys
* @param relay_vrf_story VRF story for the relay chain block
* @param cert The assignment certificate to verify
* @param backing_groups Groups that back each assigned core
* @return Delay tranche if valid, error otherwise
*/
outcome::result<DelayTranche> checkAssignmentCert(
const scale::BitVec &claimed_core_indices,
ValidatorIndex validator_index,
const runtime::SessionInfo &config,
const RelayVRFStory &relay_vrf_story,
const approval::AssignmentCertV2 &assignment,
const std::vector<GroupIndex> &backing_groups);
} // namespace kagome::parachain

namespace kagome {
class PoolHandler;
class PoolHandlerReady;
Expand Down
15 changes: 15 additions & 0 deletions core/primitives/strobe.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ namespace kagome::primitives {
}
}

void absorb(const uint8_t *src, size_t len) {
for (size_t i = 0; i < len; ++i) {
*as<uint8_t>(current_position_++) ^= src[i];
if (kStrobeR == current_position_) {
runF();
}
}
}

template <typename T, size_t N>
void overwrite(const T (&src)[N]) {
for (const auto i : src) {
Expand Down Expand Up @@ -200,6 +209,12 @@ namespace kagome::primitives {
absorb(src);
}

template <bool kMore>
void ad(const uint8_t *src, size_t len) {
beginOp<kMore, kFlag_A>();
absorb(src, len);
}

template <bool kMore, typename T, size_t N>
void metaAd(const T (&label)[N]) {
beginOp<kMore, kFlag_M | kFlag_A>();
Expand Down
13 changes: 13 additions & 0 deletions core/primitives/transcript.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ namespace kagome::primitives {
strobe_.ad<false>(msg);
}

template <typename T, size_t N>
void append_message(const T (&label)[N], const std::vector<uint8_t> &msg) {
const uint32_t data_len = msg.size();
strobe_.metaAd<false>(label);

uint8_t tmp[sizeof(data_len)];
decompose(data_len, tmp);

strobe_.metaAd<true>(tmp);
strobe_.ad<false>(reinterpret_cast<const uint8_t *>(msg.data()),
msg.size());
}

template <typename T, size_t N>
void append_message(const T (&label)[N], const uint64_t value) {
uint8_t tmp[sizeof(value)];
Expand Down
1 change: 1 addition & 0 deletions test/core/parachain/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ addtest(parachain_test
target_link_libraries(parachain_test
validator_parachain
log_configurator
vrf_provider
base_fs_test
key_store
logger
Expand Down
Loading
Loading