Skip to content

YNU-781: fix(contracts): signature validation registration#544

Merged
nksazonov merged 11 commits intofeat/channel-hub-versionfrom
fix/sig-val-cross-chain
Feb 12, 2026
Merged

YNU-781: fix(contracts): signature validation registration#544
nksazonov merged 11 commits intofeat/channel-hub-versionfrom
fix/sig-val-cross-chain

Conversation

@nksazonov
Copy link
Contributor

@nksazonov nksazonov commented Feb 12, 2026

Summary by CodeRabbit

  • New Features

    • Introduced node-level validator registry with 1-byte identifiers (0x00 for default, 0x01-0xFF for custom validators), enabling nodes to register and select trusted validators per node.
    • Added cross-chain replay protection through chain-specific validator registration and immutable registration records.
  • Documentation

    • Expanded security and protocol documentation with comprehensive coverage of validator registration, cross-chain compatibility, and trust model updates.
  • Performance

    • Adjusted compiler optimization settings to improve build efficiency.

@nksazonov nksazonov requested a review from a team as a code owner February 12, 2026 08:28
@nksazonov
Copy link
Contributor Author

@coderabbitai review

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @nksazonov, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly overhauls the signature validation mechanism within the contracts. The previous static channel-specific validator approach has been replaced with a dynamic, per-node validator registry. This change provides nodes with more control over supported signature schemes, enhances cross-chain compatibility by decoupling validator addresses from channel IDs, and streamlines the ChannelDefinition. The core contract logic has been updated to integrate this new registry, alongside comprehensive documentation and testing adjustments.

Highlights

  • Signature Validation Architecture Reworked: The system for pluggable signature validation has been refactored from a two-tier (default/channel-specific) model to a per-node validator registry. Nodes can now register multiple validators with unique 1-byte IDs (0x01-0xFF), allowing for greater flexibility and cross-chain compatibility.
  • Node Validator Registry Implementation: A new registerNodeValidator function has been added to ChannelHub.sol, enabling nodes to register signature validators on-chain using a signature-based authorization mechanism. This supports cold storage/HSM usage for node operators and ensures registrations are chain-specific.
  • Channel Definition Simplification: The ChannelDefinition struct no longer includes a direct signatureValidator address, as validator selection is now handled dynamically via the node's registry based on the signature's first byte.
  • Refactored ECDSA Signature Utilities: The BaseValidator contract has been renamed to EcdsaSignatureUtils.sol and converted into a pure library, centralizing ECDSA recovery logic for use across various validators and the ChannelHub contract.
  • Documentation Updates: Extensive updates have been made to SECURITY.md, protocol-description.md, and signature-validators.md to accurately reflect the new node validator registry architecture, its security implications, and cross-chain compatibility benefits.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • contracts/SECURITY.md
    • Updated description of pluggable signature validation to reflect the new node validator registry system.
    • Revised validator security requirements to emphasize node responsibility for registered validators.
  • contracts/foundry.toml
    • Reduced optimizer runs for the channelhub profile and ChannelHub.sol from 500 to 50 to prevent code size overflow.
  • contracts/protocol-description.md
    • Rewrote the 'Signature validation' section to detail the new per-node validator registry.
    • Added sections on validator registration, design rationale, and cross-chain compatibility.
  • contracts/signature-validators.md
    • Updated 'Validator Selection' to describe the node validator registry.
    • Added sections on validator registration, key properties, domain separation, and cross-chain compatibility.
    • Revised 'Signature Format' to use validator_id instead of validator_type.
  • contracts/src/ChannelHub.sol
    • Imported EcdsaSignatureUtils library.
    • Added ValidatorRegistered event and new error types (InvalidValidatorId, ValidatorAlreadyRegistered, ValidatorNotRegistered, InvalidSignature).
    • Removed signatureValidator field from ChannelMeta, EscrowDepositMeta, and EscrowWithdrawalMeta structs.
    • Introduced _nodeValidatorRegistry mapping to store node-registered validators.
    • Added getNodeValidator external view function.
    • Implemented registerNodeValidator function for signature-based validator registration.
    • Refactored all signature validation calls to use _selectValidatorAndFormatSig and _validateSignature or _validateChallengerSignature.
    • Removed the internal _validateSignatures and _selectValidator functions.
  • contracts/src/interfaces/Types.sol
    • Removed ISignatureValidator import and signatureValidator from ChannelDefinition struct.
    • Removed SigValidatorType enum.
    • Added DEFAULT_VALIDATOR_ID constant.
  • contracts/src/sigValidators/BaseValidator.sol
    • Renamed to contracts/src/sigValidators/EcdsaSignatureUtils.sol.
    • Refactored from an abstract contract to a pure library (EcdsaSignatureUtils).
    • Changed return types of validateEcdsaSigner and validateEcdsaSignerIsEither from ValidationResult to bool.
  • contracts/src/sigValidators/ECDSAValidator.sol
    • Updated imports to use EcdsaSignatureUtils.
    • Removed inheritance from BaseValidator.
    • Replaced direct calls to validateEcdsaSigner and validateEcdsaSignerIsEither with calls to EcdsaSignatureUtils.
  • contracts/src/sigValidators/SessionKeyValidator.sol
    • Updated imports to use EcdsaSignatureUtils.
    • Removed inheritance from BaseValidator.
    • Replaced direct calls to validateEcdsaSigner and validateEcdsaSignerIsEither with calls to EcdsaSignatureUtils.
  • contracts/test/ChannelHub_Base.t.sol
    • Imported SESSION_KEY_VALIDATOR_ID.
    • Added logic in setUp to register SessionKeyValidator for the node using the new registerNodeValidator function.
  • contracts/test/ChannelHub_crosschain.lifecycle.t.sol
    • Removed signatureValidator field from ChannelDefinition instantiations in tests.
  • contracts/test/ChannelHub_singlechain.lifecycle.t.sol
    • Removed signatureValidator field from ChannelDefinition instantiations in tests.
  • contracts/test/TestUtils.sol
    • Added SESSION_KEY_VALIDATOR_ID constant.
    • Updated signStateEip191 to use DEFAULT_VALIDATOR_ID.
    • Updated signStateEip191WithSkValidator to use SESSION_KEY_VALIDATOR_ID.
    • Added buildAndSignValidatorRegistration function to facilitate testing of validator registration.
  • contracts/test/Utils.t.sol
    • Updated imports to reflect changes in Types.sol and TestUtils.sol.
    • Removed signatureValidator field from ChannelDefinition instantiations in tests.
    • Added test_log_validatorRegistration to demonstrate and log validator registration message and signature.
  • contracts/test/sigValidators/BaseValidator.t.sol
    • Renamed to contracts/test/sigValidators/EcdsaSignatureUtils.t.sol.
    • Updated imports to EcdsaSignatureUtils.
    • Removed the TestBaseValidator helper contract.
    • Modified test cases to directly call EcdsaSignatureUtils library functions.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Refactors signature validation from a per-channel model to a per-node registry system with 1-byte validator identifiers (0x00 = default, 0x01-0xFF = node-registered). Introduces on-chain validator registration with cross-chain replay protection, removes validator fields from escrow structs, and updates all supporting contracts, validators, and test infrastructure accordingly.

Changes

Cohort / File(s) Summary
Documentation & Specifications
contracts/SECURITY.md, contracts/protocol-description.md, contracts/signature-validators.md
Comprehensive rewrite of validator architecture documentation from per-channel to per-node registry model. Adds sections on registration messaging, ECDSA recovery verification, cross-chain compatibility, domain separation, and trust model shifts. Emphasizes node-controlled validator selection and immutable on-chain registrations.
Compiler Configuration
contracts/foundry.toml
Reduces ChannelHub optimizer run count from 500 to 50, affecting code-size and gas optimization breadth.
Core Protocol & Types
contracts/src/ChannelHub.sol, contracts/src/interfaces/Types.sol
Introduces node-level validator registry with public getter and registration function. Adds ValidatorRegistered event and four new error types. Replaces validator selection via first-byte signature identifier. Removes signatureValidator field from ChannelDefinition and replaces SigValidatorType enum with DEFAULT_VALIDATOR_ID constant.
Signature Validators
contracts/src/sigValidators/ECDSAValidator.sol, contracts/src/sigValidators/SessionKeyValidator.sol, contracts/src/sigValidators/EcdsaSignatureUtils.sol
Removes BaseValidator inheritance; converts to direct delegation via EcdsaSignatureUtils. Converts BaseValidator to public library EcdsaSignatureUtils. Adds explicit validateSignature and validateChallengerSignature functions to ECDSA validator.
Test Base Infrastructure
contracts/test/ChannelHub_Base.t.sol, contracts/test/TestUtils.sol
Adds validator registration step in test setup via registerNodeValidator. Introduces buildAndSignValidatorRegistration helper and SESSION_KEY_VALIDATOR_ID constant. Replaces SigValidatorType usage with explicit ID constants.
Lifecycle & Utility Tests
contracts/test/ChannelHub_crosschain.lifecycle.t.sol, contracts/test/ChannelHub_singlechain.lifecycle.t.sol, contracts/test/Utils.t.sol
Removes signatureValidator field assignments from ChannelDefinition initializations across multiple test cases. Updates signature encoding to use validator ID constants. Adds new test for validator registration message logging.
Validator Unit Tests
contracts/test/sigValidators/EcdsaSignatureUtils.t.sol
Renames test suite from BaseValidatorTest_* to EcdsaSignatureUtilsTest_*. Updates all test calls to use library functions directly instead of test validator wrapper methods.

Sequence Diagram(s)

sequenceDiagram
    participant Node as Node
    participant Hub as ChannelHub
    participant Registry as Validator Registry
    participant Utils as EcdsaSignatureUtils

    Node->>Hub: registerNodeValidator(node, validatorId, validator, signature)
    activate Hub
    Hub->>Utils: validateEcdsaSigner(message, signature, node)
    activate Utils
    Utils-->>Hub: bool (valid)
    deactivate Utils
    
    alt Signature Valid
        Hub->>Registry: Store validator mapping
        Hub->>Hub: Emit ValidatorRegistered
        Note over Hub: (node, validatorId) -> validator
    else Signature Invalid
        Hub-->>Node: Revert InvalidSignature
    end
    deactivate Hub
Loading
sequenceDiagram
    participant User as User/Relayer
    participant Hub as ChannelHub
    participant Validator as Validator (via Registry)
    participant Utils as EcdsaSignatureUtils

    User->>Hub: submit signature (first byte = validatorId)
    activate Hub
    
    Hub->>Hub: _selectValidatorAndFormatSig(signature, node)
    Note over Hub: Extract validatorId from byte 0<br/>Lookup validator from registry<br/>Strip first byte from signature
    
    activate Validator
    Hub->>Validator: validateSignature(channelId, signingData, sig, participant)
    deactivate Validator
    
    activate Utils
    Validator->>Utils: validateEcdsaSigner(message, signature, participant)
    Utils-->>Validator: bool (valid)
    deactivate Utils
    
    alt Signature Valid
        Hub->>Hub: Process transaction
    else Invalid
        Hub-->>User: Revert InvalidSignature
    end
    deactivate Hub
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly Related PRs

  • YNU-664: feat(contracts): sig val module #538: Introduces the pluggable per-channel validator model that this PR refactors into a per-node registry with on-chain registration, forming part of the same validation subsystem evolution.

Suggested Labels

ready

Suggested Reviewers

  • dimast-x
  • philanton
  • alessio

Poem

🐰 A registry springs up, validators now fly,

Node-keyed with IDs, no need for goodbye,

One byte tells all which validator's true,

Cross-chains stay safe with their proof signed through! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: implementing signature validation registration, which is the core theme across all modified files including documentation, validator architecture refactoring, and new registration API.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/sig-val-cross-chain

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the signature validation mechanism, moving from a channel-specific validator to a more flexible node-based validator registry, which aims to enhance cross-chain compatibility and modularity. However, this introduces a critical vulnerability: by allowing a node to control the validator, it can unilaterally bypass user signatures, effectively gaining full control over user funds within any channel. It is strongly recommended that this change be reverted, and the validator remain part of the immutable channel definition or require explicit approval from all participants. Additionally, consider reducing code duplication in ChannelHub.sol, and note that the reduction in foundry.toml's optimizer_runs may slightly increase gas costs.

_selectValidatorAndFormatSig(initState.userSig, def.node);
_validateSignature(channelId, initState, userSigData, def.user, userValidator);
(ISignatureValidator nodeValidator, bytes calldata nodeSigData) =
_selectValidatorAndFormatSig(initState.nodeSig, def.node);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this way node also supports now all registered validators?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we discussed, we cannot disable previously registered ones on the contract. But the node can simply stop signing new states signed with the validator it no longer supports

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

@nksazonov nksazonov merged commit e67a1f6 into feat/channel-hub-version Feb 12, 2026
3 checks passed
@nksazonov nksazonov deleted the fix/sig-val-cross-chain branch February 12, 2026 13:36
nksazonov added a commit that referenced this pull request Feb 12, 2026
* docs(contracts): update signature validator approach

* refactor(contracts): reorg BaseValidator into lib

* docs(contracts): add chainId to val registration msg

* feat(contracts): add sig val registration

* test(contracts): sig val registration

* build(contracts): reduce number of optimizer runs for Custody

* docs(contracts): add per-channel validator bitmask

* feat(contracts): add per-channel sig val bitmask

* refactor(contracts): remove verifyChallengerSig

* fix(contracts/Types): rename default val to sig val

* chore(contracts): rename states to ledgers, run forge fmt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants