-
Notifications
You must be signed in to change notification settings - Fork 3
Hash sig #34
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
Hash sig #34
Conversation
remove num_validators, update genesis_time, and enhance genesis state generation
…k methods in ValidatorKeysManifestMock
2a1f827 to
0230596
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces XMSS (eXtended Merkle Signature Scheme) hash-based signatures to replace placeholder signatures in the consensus protocol. The implementation integrates the qdrvm-crates dependency for cryptographic operations and refactors the validator key management system.
Key Changes:
- Adds XMSS signature support through new
crypto::xmssmodule with provider interface, types, and utility functions - Removes
num_validatorsfrom Config in favor of dynamic validator list stored in State - Implements
ValidatorKeysManifestfor loading and managing validator public keys from YAML manifests - Refactors signature verification throughout the fork choice and state transition systems
Reviewed changes
Copilot reviewed 57 out of 60 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
| vcpkg.json | Adds qdrvm-crates dependency for XMSS cryptography |
| vcpkg-overlay/qdrvm-crates/* | Configures qdrvm-crates package with c_hash_sig binding |
| src/crypto/xmss/* | Implements XMSS provider, types, and key loading utilities |
| src/app/validator_keys_manifest | Adds validator key manifest loading and management |
| src/types/{config,state,signature,validator}.hpp | Refactors types to use XMSS keys and dynamic validator lists |
| src/blockchain/state_transition_function.* | Updates genesis state generation to populate validators from manifest |
| src/blockchain/fork_choice.* | Implements XMSS signature verification for blocks and attestations |
| tests/unit/crypto/* | Adds XMSS provider tests |
| tests/unit/blockchain/* | Updates tests for new validator registry and key manifest interfaces |
| tests/mock/* | Adds mocks for XMSS provider and validator keys manifest |
| example/1-network/genesis/* | Updates example configuration with XMSS keys and manifest |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.
| ValidatorIndex validatorCount() const { | ||
| return config.num_validators; | ||
| return validators.size(); |
Copilot
AI
Nov 26, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The validatorCount() method now returns validators.size() instead of config.num_validators. However, this could be problematic if the validators vector is not properly initialized or if it's empty. In scenarios where the state is constructed but validators haven't been populated yet, this would return 0, potentially causing issues in code that depends on validator counts. Consider adding validation to ensure validators is populated, or documenting the initialization requirements clearly.
src/types/signed_attestation.hpp
Outdated
| auto payload = sszHash(attestation); | ||
| return SignedAttestation{.message = attestation, .signature = {}}; |
Copilot
AI
Nov 26, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sszHash(attestation) is computed but assigned to payload which is then not used in the stub implementation. This unused variable suggests incomplete implementation. Either the payload should be used for actual signing, or it should be removed if this is intentionally a stub.
| "Failed to produce block for slot {}: {}", | ||
| current_slot, | ||
| res.error()); | ||
| time_ += 1; |
Copilot
AI
Nov 26, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent time increment logic. When produceBlockWithSignatures fails (line 625), the code increments time and continues (line 630). However, the normal flow already increments time at line 705. This means that when block production fails, time is incremented twice in one iteration - once at line 630 and once at line 705. This will cause the node to skip an interval, which could lead to timing issues and missed attestation opportunities.
| time_ += 1; |
| for (size_t i = 0; i < registry->allValidatorsIndices().size(); ++i) { | ||
| auto opt_pubkey = validator_keys_manifest->getXmssPubkeyByIndex(i); | ||
| if (not opt_pubkey) { | ||
| continue; | ||
| } | ||
| result.validators.push_back(Validator{.pubkey = *opt_pubkey}); | ||
| } |
Copilot
AI
Nov 26, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The genesis state generation iterates through validator indices using registry->allValidatorsIndices().size() (line 74) but then looks up the public key by that loop index i (line 75). This assumes that validator indices are contiguous starting from 0, which may not be the case. If allValidatorsIndices() returns a set like {5, 10, 15}, the code will look up indices 0, 1, 2 instead of 5, 10, 15, resulting in missing or incorrect validators. The loop should iterate over the actual indices returned by allValidatorsIndices(), not just its size.
|
|
||
| // Check reasonable sizes | ||
| EXPECT_GT(keypair.public_key.size(), 0); | ||
| EXPECT_GT(keypair.private_key.size(), 0); |
Copilot
AI
Nov 26, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to line 30, this test checks keypair.private_key.size() on line 34, but XmssPrivateKey is a std::shared_ptr which doesn't have a size() method. This test will not compile.
| return result; | ||
| } | ||
|
|
||
|
|
Copilot
AI
Nov 26, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Empty line added at line 710. While not harmful, this extra blank line is inconsistent with the surrounding code formatting and should be removed.
| for (auto i = num_empty_slots; i > 0; --i) { | ||
| state.historical_block_hashes.push_back(kZeroHash); | ||
| } | ||
|
|
||
| // Build new justified slots list | ||
| // | ||
| // Genesis block is always justified | ||
| state.justified_slots.push_back(is_genesis_parent); | ||
|
|
||
| // Mark empty slots as not justified | ||
| for (auto i = num_empty_slots; i > 0; --i) { |
Copilot
AI
Nov 26, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The loop variable i is declared as auto which will deduce to uint64_t (type of num_empty_slots). However, the loop counts down with --i and checks i > 0. If num_empty_slots is 0, the loop won't execute, which is correct. However, using an unsigned type in a countdown loop is a code smell - if the logic ever changes and i reaches 0 and then decrements, it will wrap around to the maximum value. Consider using a signed type or restructuring the loop to count up instead.
| return xmss_keypair_.value(); | ||
| } | ||
|
|
||
|
|
Copilot
AI
Nov 26, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Extra blank line at line 68. This creates inconsistent spacing in the method implementation.
src/types/config.hpp
Outdated
| SSZ_CONT(num_validators, genesis_time); | ||
| bool operator==(const Config &) const = default; | ||
| SSZ_CONT(genesis_time); | ||
|
|
Copilot
AI
Nov 26, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trailing whitespace on line 18. This should be removed for code cleanliness.
| ValidatorRegistry::ValidatorIndices | ||
| ValidatorRegistryImpl::allValidatorsIndices() const { | ||
| ValidatorIndices all_indices; | ||
| all_indices.reserve(index_to_node_.size()); |
Copilot
AI
Nov 26, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reserve call on line 92 is inefficient for a set container. ValidatorIndices appears to be a set (based on the insert call on line 94), and sets don't support reserve() since they're typically implemented as red-black trees. This will either fail to compile or the reserve call has no effect. If ValidatorIndices is actually an unordered_set, then reserve would work but the size hint would be wrong since we're reserving based on index_to_node_.size() but then inserting into the set. Sets automatically handle capacity, so this line should be removed.
| all_indices.reserve(index_to_node_.size()); | |
| // reserve() is not needed for set containers |
src/types/signed_attestation.hpp
Outdated
| /** | ||
| * Stub method to sign vote. | ||
| */ | ||
| inline SignedAttestation signAttestation(Attestation attestation) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not used, can be removed
Signed-off-by: turuslan <[email protected]>
Signed-off-by: turuslan <[email protected]>
Signed-off-by: turuslan <[email protected]>
Signed-off-by: turuslan <[email protected]>
Update up to the leanSpec 49f70c7: