Skip to content

feat: remote signing#2078

Merged
tac0turtle merged 35 commits intofeature/exec_apifrom
marko/remote_signer
Mar 31, 2025
Merged

feat: remote signing#2078
tac0turtle merged 35 commits intofeature/exec_apifrom
marko/remote_signer

Conversation

@tac0turtle
Copy link
Contributor

@tac0turtle tac0turtle commented Mar 14, 2025

closes #1125
add remote signing as an option.

This PR consists of:

  • Local implementation
  • Remote implementation

Summary by CodeRabbit

  • New Features

    • Introduced a secure file-based signing mechanism with passphrase support.
    • Added flexible signing options through new configuration flags for signer type, key path, and passphrase.
  • Documentation

    • Provided comprehensive guides and examples for using the secure file signer.
  • Refactor

    • Streamlined cryptographic signing and node initialization, improving error handling.
  • Chores

    • Updated dependencies and configuration files to enhance overall stability and performance.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 14, 2025

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.

Walkthrough

This pull request refactors the cryptographic signing mechanism across multiple components. The change shifts from using the concrete type crypto.PrivKey to the abstract signer.Signer interface in managers, nodes, and tests. It also introduces new configurations and command‐line flags for a file-based signer, updates dependency configurations to remove CometBFT and adjust protobuf usage, and includes new implementations and tests for both file system and noop signers as well as a protobuf-based signer service.

Changes

File(s) Change Summary
block/manager.go, node/full.go, node/node.go Updated signing parameters from crypto.PrivKey to signer.Signer in structs and function signatures.
block/manager_test.go, node/node_integration_test.go, node/helpers_test.go, node/node_test.go Modified tests to use the new signer abstraction (including noop and remote signers) and adjusted signature verification.
cmd/rollkit/commands/init.go, cmd/rollkit/commands/run_node.go, cmd/rollkit/commands/run_node_test.go Added logic and flags for initializing a file-based signer; removed mock sequencer server functionality.
buf.gen.yaml, buf.yaml, pkg/config/config.go, pkg/config/config_test.go, pkg/config/defaults.go Revised build and configuration files: updated versions, removed obsolete sections, added new signer config flags and defaults.
go.mod, sequencers/single/go.mod, sequencers/single/queue.go Removed CometBFT dependencies, replaced with alternatives, added google.golang.org/protobuf dependency, and changed protobuf marshaling to use proto.Marshal/proto.Unmarshal.
pkg/signer/noop/doc.go, pkg/signer/noop/signer.go, pkg/signer/noop/signer_test.go Introduced a Noop signer implementation for remote signing, including its tests and documentation.
pkg/signer/file/README.md, pkg/signer/file/doc.go, pkg/signer/file/example_test.go, pkg/signer/file/local.go Added a secure FileSystem signer implementation with encryption, key generation, and comprehensive documentation and examples.
pkg/signer/signer.go, proto/rollkit/v1/signer.proto, types/pb/rollkit/v1/v1connect/signer.connect.go Defined a new Signer interface and set up protobuf messages and a Connect RPC service for signer operations.
types/hashing.go Updated the hashing logic to use a custom sha256-based function with a new leaf prefix, eliminating the dependency on the merkle package.
specs/lazy-adr/adr-017-node-pruning.md Reformatted document content for better consistency and readability without functional changes.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant I as InitCmd
    participant FS as FileSystemSigner

    U->>I: Set signer type ("file") & passphrase flag
    I->>I: Check if node is aggregator and signer type is "file"
    I->>I: Retrieve signer passphrase from flags
    I->>FS: Call NewFileSystemSigner(keyPath, passphrase)
    FS-->>I: Return signer instance or error
    I->>U: Proceed with node initialization (or return error)
Loading

Assessment against linked issues

Objective Addressed Explanation
Remove CometBFT dependencies [#1125]
Replace crypto/merkle with a direct sha256 implementation [#1125]
Update configuration and module structure to remove CometBFT-specific configs [#1125]

Suggested labels

T:dependencies

Suggested reviewers

  • tuxcanfly
  • yarikbratashchuk
  • gupadhyaya
  • MSevey

Poem

Oh, what a hop, a bounce so light,
From keys of old to signers bright!
My whiskers twitch with pure delight,
As files and tests leap into flight.
Secure and nimble, we now run free –
A happy rabbit sings: “Code bliss, oui!”
🐇✨


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 14, 2025

PR Preview Action v1.6.0

🚀 View preview at
https://rollkit.github.io/rollkit/pr-preview/pr-2078/

Built to branch gh-pages at 2025-03-26 14:44 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@codecov
Copy link

codecov bot commented Mar 14, 2025

Codecov Report

Attention: Patch coverage is 10.97561% with 730 lines in your changes missing coverage. Please review.

Project coverage is 22.81%. Comparing base (2262207) to head (0f82365).
Report is 12 commits behind head on feature/exec_api.

Files with missing lines Patch % Lines
pkg/remote_signer/v1/signer.pb.go 0.00% 652 Missing ⚠️
pkg/remote_signer/file/local.go 60.00% 40 Missing and 20 partials ⚠️
pkg/remote_signer/grpc/server.go 0.00% 18 Missing ⚠️
Additional details and impacted files
@@                 Coverage Diff                  @@
##           feature/exec_api    #2078      +/-   ##
====================================================
- Coverage             24.11%   22.81%   -1.31%     
====================================================
  Files                    52       57       +5     
  Lines                  8231     9112     +881     
====================================================
+ Hits                   1985     2079      +94     
- Misses                 6089     6851     +762     
- Partials                157      182      +25     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@tac0turtle tac0turtle marked this pull request as ready for review March 26, 2025 14:45
@RollkitBot RollkitBot requested review from a team, MSevey and tzdybal and removed request for a team March 26, 2025 14:45
@tac0turtle tac0turtle requested review from randygrok and removed request for MSevey and tzdybal March 26, 2025 14:45
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🔭 Outside diff range comments (1)
pkg/config/config_test.go (1)

91-105: ⚠️ Potential issue

Fix failing test related to default Aggregator value

The pipeline failure indicates that TestDefaultNodeConfig is failing because it expects def.Node.Aggregator to be true on line 21, but the default value has been changed to false in defaults.go.

Apply this fix to update the test to match the new default value:

-	assert.Equal(t, true, def.Node.Aggregator)
+	assert.Equal(t, false, def.Node.Aggregator)
🧹 Nitpick comments (13)
pkg/signer/file/README.md (1)

23-44: Avoid hardcoded passphrases in code examples

While the example clearly demonstrates the API usage, it shows a hardcoded passphrase which isn't recommended for production code.

Consider updating the example to show obtaining the passphrase securely, like:

-// Create a new signer (or load existing keys)
-passphrase := []byte("your-secure-passphrase")
+// Create a new signer (or load existing keys)
+// In production, obtain passphrase securely (e.g., environment variables, secure prompt)
+passphrase := obtainPassphraseSecurely() // Returns []byte
types/hashing.go (1)

8-10: Leaf node prefix for hashing standardization.

The introduction of leafPrefix is a good practice used in Merkle tree implementations to differentiate leaf node hashes from internal node hashes, improving the cryptographic properties of the hash tree.

Consider adding a comment explaining the purpose of this prefix constant, particularly noting its role in Merkle tree hashing if that's the intent.

pkg/signer/signer.go (1)

7-14: Well-designed Signer interface.

The Signer interface is:

  1. Appropriately minimal with just the essential methods
  2. Well-documented with clear method descriptions
  3. Using standard cryptographic patterns (byte slices for messages and signatures)
  4. Built on established libp2p cryptographic types

This interface will effectively support the PR's goal of implementing both local and remote signing options.

Consider adding documentation about the expected signature format or encoding, if there are specific requirements that implementers need to follow.

pkg/signer/file/doc.go (1)

1-35: Good documentation but improve error handling examples

The documentation clearly illustrates how to use the file-based signer implementation, which is helpful for users. However, using panic in example code isn't a best practice for production applications.

Consider updating the examples to demonstrate proper error handling rather than panicking:

// Create or load a signer
signer, err := NewFileSystemSigner(keyPath, passphrase)
if err != nil {
-	panic(err)
+	// Handle error appropriately, e.g., log and return
+	log.Printf("Failed to create signer: %v", err)
+	return err
}

Similarly update the other error handling examples to show graceful error handling patterns rather than panics.

pkg/signer/noop/signer.go (2)

16-23: Inconsistency between comment and implementation

The comment on line 10 states that NoopSigner "generates a new Ed25519 key pair for each instance," but the implementation accepts an existing private key instead of generating one.

-// NoopSigner implements the remote_signer.Signer interface.
-// It generates a new Ed25519 key pair for each instance.
+// NoopSigner implements the signer.Signer interface.
+// It uses an existing private key for signing operations.

17-23: Consider adding input validation for the private key

The function doesn't validate if the provided private key is nil or of the expected type, which could lead to runtime errors.

 func NewNoopSigner(privKey crypto.PrivKey) (signer.Signer, error) {
+	if privKey == nil {
+		return nil, fmt.Errorf("private key cannot be nil")
+	}
+
+	// Optional: Check if the key is of the expected type (e.g., Ed25519)
+	if privKey.Type() != crypto.Ed25519 {
+		return nil, fmt.Errorf("expected Ed25519 key, got %s", privKey.Type())
+	}
+
 	return &NoopSigner{
 		privKey: privKey,
 		pubKey:  privKey.GetPublic(),
 	}, nil
 }
pkg/signer/file/example_test.go (2)

43-43: Redundant passphrase reinitialization

The passphrase is already defined at line 16 with the same value, so reinitializing it here is unnecessary.

-	passphrase = []byte("test-passphrase-123")
 	// Create a new signer instance (this will load the existing keys)
 	signer2, err := NewFileSystemSigner(keyPath, passphrase)

67-103: Example function could be improved for documentation

The Example function is helpful but has some issues:

  1. It uses panic for error handling, which isn't a best practice for examples
  2. It doesn't print any output, so it won't work as a testable example in Go documentation

Consider modifying it to follow Go's example function conventions:

 // Example demonstrates how to use the FileSystemSigner
 func Example() {
 	// In a real application, you would use a secure passphrase
 	passphrase := []byte("your-secure-passphrase")
 	keyPath := "/path/to/secure/keys.json"
 
 	// Create or load a signer
 	signer, err := NewFileSystemSigner(keyPath, passphrase)
-	if err != nil {
-		panic(err)
-	}
+	if err != nil {
+		fmt.Println("Error creating signer:", err)
+		return
+	}
 
 	// Sign a message
 	message := []byte("Message to sign")
 	signature, err := signer.Sign(message)
-	if err != nil {
-		panic(err)
-	}
+	if err != nil {
+		fmt.Println("Error signing message:", err)
+		return
+	}
 
 	// Get the public key
 	pubKey, err := signer.GetPublic()
-	if err != nil {
-		panic(err)
-	}
+	if err != nil {
+		fmt.Println("Error getting public key:", err)
+		return
+	}
 
 	// Verify the signature (typically done by another party)
 	valid, err := pubKey.Verify(message, signature)
-	if err != nil {
-		panic(err)
-	}
+	if err != nil {
+		fmt.Println("Error verifying signature:", err)
+		return
+	}
 
 	if valid {
-		// Signature is valid
+		fmt.Println("Signature is valid")
 	} else {
-		// Signature is invalid
+		fmt.Println("Signature is invalid")
 	}
+	// Output: Signature is valid
 }
cmd/rollkit/commands/init.go (1)

69-95: Good implementation of local file signer initialization.

The code properly initializes a local file signer when the signer type is "file" and the node is an aggregator. It checks for a passphrase, creates the necessary directory, and initializes the signer.

Consider adding a verbose log message indicating successful signer initialization to improve user feedback.

// Initialize the signer
_, err = file.NewFileSystemSigner(config.Signer.SignerPath, []byte(passphrase))
if err != nil {
    return fmt.Errorf("failed to initialize signer: %w", err)
}
+fmt.Printf("Successfully initialized signer at %s\n", config.Signer.SignerPath)
cmd/rollkit/commands/run_node.go (1)

77-92: Implement local file signer selection
The branch checks the configured signer type and initializes accordingly. Using panic for unimplemented gRPC might be more robustly handled by returning an error, but for now it clearly conveys it's unsupported.

Would you like me to sketch out a basic gRPC signer implementation or fallback error handling?

pkg/signer/file/local.go (3)

67-89: Generating Ed25519 key pairs followed by immediate encryption is a good practice.

No issues observed. The function generateAndSaveKeys ensures atomic creation of new keys. Minor note: consider logging success or failures for auditing & troubleshooting.


171-218: Decryption steps logically mirror encryption.

Error messages are descriptive. One nitpick: you could log or wrap the error more thoroughly if passphrase-based decryption fails.


271-284: Fallback key derivation provides backward compatibility but weaker security.

Ensure that users are informed of the weaker approach whenever old key files are used. Possibly consider a migration workflow.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8c67e2 and 199d511.

⛔ Files ignored due to path filters (6)
  • go.sum is excluded by !**/*.sum
  • pkg/signer/v1/signer.pb.go is excluded by !**/*.pb.go
  • sequencers/single/go.sum is excluded by !**/*.sum
  • types/pb/rollkit/v1/rollkit.pb.go is excluded by !**/*.pb.go
  • types/pb/rollkit/v1/signer.pb.go is excluded by !**/*.pb.go
  • types/pb/rollkit/v1/state.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (31)
  • block/manager.go (4 hunks)
  • block/manager_test.go (4 hunks)
  • buf.gen.yaml (1 hunks)
  • buf.yaml (1 hunks)
  • cmd/rollkit/commands/init.go (3 hunks)
  • cmd/rollkit/commands/run_node.go (3 hunks)
  • cmd/rollkit/commands/run_node_test.go (0 hunks)
  • go.mod (3 hunks)
  • node/full.go (5 hunks)
  • node/full_node_integration_test.go (7 hunks)
  • node/helpers_test.go (3 hunks)
  • node/node.go (3 hunks)
  • node/node_integration_test.go (4 hunks)
  • node/node_test.go (3 hunks)
  • pkg/config/config.go (4 hunks)
  • pkg/config/config_test.go (1 hunks)
  • pkg/config/defaults.go (2 hunks)
  • pkg/signer/file/README.md (1 hunks)
  • pkg/signer/file/doc.go (1 hunks)
  • pkg/signer/file/example_test.go (1 hunks)
  • pkg/signer/file/local.go (1 hunks)
  • pkg/signer/noop/doc.go (1 hunks)
  • pkg/signer/noop/signer.go (1 hunks)
  • pkg/signer/noop/signer_test.go (1 hunks)
  • pkg/signer/signer.go (1 hunks)
  • proto/rollkit/v1/signer.proto (1 hunks)
  • sequencers/single/go.mod (1 hunks)
  • sequencers/single/queue.go (3 hunks)
  • specs/lazy-adr/adr-017-node-pruning.md (14 hunks)
  • types/hashing.go (2 hunks)
  • types/pb/rollkit/v1/v1connect/signer.connect.go (1 hunks)
💤 Files with no reviewable changes (1)
  • cmd/rollkit/commands/run_node_test.go
🧰 Additional context used
🧬 Code Definitions (12)
node/node_integration_test.go (2)
pkg/signer/noop/signer.go (1)
  • NewNoopSigner (17-23)
node/helpers.go (1)
  • InitFiles (129-145)
node/helpers_test.go (2)
pkg/signer/noop/signer.go (1)
  • NewNoopSigner (17-23)
node/helpers.go (1)
  • InitFiles (129-145)
types/hashing.go (1)
types/header.go (1)
  • Hash (18-18)
cmd/rollkit/commands/init.go (2)
pkg/config/config.go (1)
  • FlagSignerPassphrase (113-113)
pkg/signer/file/local.go (1)
  • NewFileSystemSigner (39-65)
pkg/signer/noop/signer.go (1)
pkg/signer/signer.go (1)
  • Signer (8-14)
pkg/signer/noop/signer_test.go (1)
pkg/signer/noop/signer.go (1)
  • NewNoopSigner (17-23)
pkg/signer/file/example_test.go (1)
pkg/signer/file/local.go (1)
  • NewFileSystemSigner (39-65)
node/node_test.go (2)
pkg/signer/noop/signer.go (1)
  • NewNoopSigner (17-23)
node/helpers.go (1)
  • InitFiles (129-145)
pkg/config/config.go (2)
pkg/signer/signer.go (1)
  • Signer (8-14)
types/pb/rollkit/v1/rollkit.pb.go (3)
  • Signer (294-302)
  • Signer (315-315)
  • Signer (330-332)
pkg/signer/file/local.go (1)
pkg/signer/signer.go (1)
  • Signer (8-14)
node/full.go (2)
pkg/signer/signer.go (1)
  • Signer (8-14)
types/pb/rollkit/v1/rollkit.pb.go (3)
  • Signer (294-302)
  • Signer (315-315)
  • Signer (330-332)
node/full_node_integration_test.go (2)
pkg/signer/noop/signer.go (1)
  • NewNoopSigner (17-23)
node/helpers.go (1)
  • InitFiles (129-145)
🪛 GitHub Actions: CI and Release
pkg/config/config_test.go

[error] 21-21: TestDefaultNodeConfig failed: Not equal: expected: true, actual: false.

proto/rollkit/v1/signer.proto

[error] 29-29: Format diff -1/+1. The file is missing a newline at the end of the file.

🪛 LanguageTool
specs/lazy-adr/adr-017-node-pruning.md

[grammar] ~890-~890: If ‘choose’ is used as a verb, it usually requires the infinitive.
Context: ...Management**: - Operators can choose pruning strategies that fit their needs - Su...

(AFFORD_VBG)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Summary
🔇 Additional comments (100)
buf.gen.yaml (1)

11-12: New plugin input configuration added.

The addition of the inputs section specifying the "proto" directory aligns with modern Protocol Buffer tooling conventions. This change ensures the build system knows exactly where to find the proto definition files.

specs/lazy-adr/adr-017-node-pruning.md (1)

114-116: Formatting improvements increase readability

The consistent bullet point styling (using dashes instead of asterisks) and improved indentation enhance the document's readability while maintaining the content's integrity.

Also applies to: 118-120, 127-129, 131-133, 137-141, 142-145, 147-150, 154-156, 158-161, 163-165, 169-171, 173-175, 177-180, 187-191, 192-195, 196-199, 200-203, 387-394, 399-421

sequencers/single/queue.go (3)

12-12: Import updated for Protocol Buffer handling

The addition of the direct import for google.golang.org/protobuf/proto aligns with the change in serialization approach.


49-49: Batch serialization updated to use the proto package directly

Changed from the previous approach (likely pbBatch.Marshal()) to using proto.Marshal(pbBatch), which follows the recommended Go Protocol Buffer API usage pattern.


112-112: Batch deserialization updated to use the proto package directly

Changed from the previous approach (likely pbBatch.Unmarshal(result.Value)) to proto.Unmarshal(result.Value, pbBatch), which follows the recommended Go Protocol Buffer API usage pattern.

pkg/signer/file/README.md (2)

1-78: Comprehensive documentation for the new FileSystem Signer

The documentation thoroughly covers the security features, usage patterns, and implementation details for the new secure filesystem-based signer implementation.


46-52: Good security considerations for production use

The documentation appropriately highlights important security considerations for production use, such as using stronger KDFs (Argon2 or PBKDF2) and implementing secure passphrase handling.

types/hashing.go (3)

5-6: Added import for hash interface support.

The addition of the "hash" package is necessary to support the new leafHashOpt function's parameter type.


27-28: Improved hashing implementation.

The change to use leafHashOpt with the leaf prefix enhances the hashing approach for Data objects.


30-35: Well-structured hashing helper function.

The leafHashOpt function is well-designed:

  1. It accepts a hash implementation, supporting flexibility
  2. It properly resets the hash state before use
  3. It follows best practices by prefixing leaf data
  4. It properly handles hash finalization

The implementation aligns with cryptographic best practices.

go.mod (3)

70-70: Added indirect dependency on gogo/protobuf.

This is a natural dependency for using gogoproto and is correctly marked as indirect.


36-36:

Details

✅ Verification successful

Direct dependency on golang.org/x/crypto added.

This matches the PR's intention to implement remote signing functionality, requiring direct access to cryptographic primitives rather than accessing them through CometBFT.

Verify the security status of this crypto package version:


🏁 Script executed:

#!/bin/bash
# Check for known vulnerabilities in golang.org/x/crypto v0.33.0
curl -s "https://pkg.go.dev/vuln/GO-2023-2185" | grep -A 5 "golang.org/x/crypto v0.33.0"
curl -s "https://pkg.go.dev/vuln/list" | grep -A 2 "golang.org/x/crypto"

Length of output: 2145


Security Verification Complete: Direct Dependency on golang.org/x/crypto v0.33.0 Approved

  • The addition of golang.org/x/crypto v0.33.0 in go.mod (line 36) supports the PR’s goal of enabling remote signing by accessing low-level cryptographic primitives directly.
  • The vulnerability checks via pkg.go.dev did not flag any critical issues specific to this version for our typical usage.
  • Note: While some generic vulnerability listings mention potential issues (e.g., panics on malformed inputs in 32-bit environments), these scenarios are not applicable in our case.

17-17:

Details

❓ Verification inconclusive

Major dependency change: CometBFT replaced with gogoproto.

This change shifts from using the CometBFT framework to using the Cosmos gogoproto implementation directly.

Please verify that all CometBFT functionality that was previously utilized has appropriate replacements or alternatives in the new dependency structure.


🌐 Web query:

Are there any known compatibility issues between gogoproto v1.7.0 and cometbft?

💡 Result:

There are known compatibility considerations between gogoproto and CometBFT (formerly Tendermint Core) due to differing Protobuf implementation approaches, though no direct incompatibilities are explicitly documented for v1.7.0. Key points:

  1. Protobuf Versioning Constraints:

    • gogoproto-generated code requires matching runtime library versions ([3][6]). CometBFT's ABCI message definitions in [12][18] use standard Protobuf types, but mixed gogoproto/golang-protobuf usage could cause serialization issues ([7][16]).
  2. Code Generation Incompatibilities:

    • The gogoproto fork introduces custom optimizations (like gogoproto.nullable and gogoproto.customtype in [18]) that may conflict with CometBFT's expected Protobuf message formats if not properly aligned ([3][9]).
  3. Address Encoding Conflicts:

    • CometBFT uses Bech32m encoding for addresses, while some Cosmos chains using gogoproto (like Noble in [9]) require Bech32. This could affect IBC integrations when serializing addresses in Protobuf messages ([9][12]).
  4. Community Migration Trends:

    • Major projects like Thanos and Prometheus have moved away from gogoproto due to maintenance concerns and compatibility challenges with standard Protobuf tooling ([7][16]). CometBFT's ecosystem is likely following similar patterns.

To mitigate risks:

# Ensure consistent Protobuf toolchain versions
go get github.com/cosmos/gogoproto@v1.7.0
protoc --gogo_out=paths=source_relative:. -I=. -I=$GOPATH/src ./cometbft/**/*.proto

Always validate serialization/deserialization flows between gogoproto-enhanced types and CometBFT's native ABCI messages during integration testing.

Citations:


Verify Protobuf Compatibility with the gogoproto Migration

The change to github.com/cosmos/gogoproto v1.7.0 replaces CometBFT with the Cosmos gogoproto implementation. While no direct incompatibilities have been explicitly documented for v1.7.0, known compatibility considerations—such as differences in Protobuf versioning, code generation (e.g., handling of gogoproto.nullable and custom types), and address encoding—may impact components that previously relied on CometBFT’s Protobuf definitions.

  • Protobuf Runtime & Code Generation: Ensure that the Protobuf runtime versions are consistent and that any code generation differences do not break serialization of CometBFT’s previously used message formats.
  • Address Encoding: Verify that any discrepancies between Bech32 and Bech32m encoding do not affect the functionality, particularly for IBC integrations.
  • Integration Testing: It's crucial to run thorough integration tests to confirm that all CometBFT functionality has an appropriate replacement in this new dependency structure.

Please review the integration points where CometBFT functionality was used and validate that these areas perform as expected with gogoproto v1.7.0.

pkg/signer/noop/doc.go (1)

1-7: Clear documentation for the no-op signer package.

The documentation clearly explains the purpose of this package as implementing a no-op signer for testing and development scenarios. This aligns well with the PR objective of adding remote signing capabilities.

pkg/signer/signer.go (1)

3-5: Appropriate import for cryptographic functionality.

The import of github.com/libp2p/go-libp2p/core/crypto is correct for utilizing the libp2p cryptographic types, particularly crypto.PubKey.

pkg/config/config_test.go (1)

91-91: Updated expected flag count correctly

The change from 36 to 39 flags accurately reflects the addition of three new flags related to remote signing functionality (likely FlagSignerType, FlagSignerPath, and FlagSignerPassphrase).

pkg/config/defaults.go (2)

78-81:

Details

❓ Verification inconclusive

Good addition of default signer configuration

Adding default signer configuration with SignerType: "file" and an empty SignerPath makes the default signing mechanism explicit. This aligns well with the PR's objective of adding remote signing capabilities.

Please ensure that the code handles the case of an empty SignerPath gracefully, either by:

  1. Generating a default path
  2. Providing clear error messages if a path is required
  3. Documenting how this default configuration behaves

🏁 Script executed:

#!/bin/bash
# Check how the code handles empty SignerPath
rg -A 10 "SignerPath.*==" 

Length of output: 27


Action Required: Verify Empty SignerPath Handling

The default configuration now explicitly sets SignerPath to an empty string, which aligns with the PR’s objective by clearly exposing the default signer behavior. However, our automated grep test did not reveal any code handling the empty value. Please manually verify that the code gracefully manages an empty SignerPath (e.g., by auto-generating a default path, issuing a clear error when a valid path is expected, or providing appropriate documentation on its handling).

  • Location: pkg/config/defaults.go (lines 78–81)
  • Verification Needed: Confirm downstream components either resolve an empty SignerPath correctly or emit a helpful error message, or that the behavior is well documented.

55-55:

Details

❓ Verification inconclusive

Breaking change: Default Aggregator value changed from true to false

Changing the default value of Aggregator from true to false is a breaking change that affects backward compatibility. This causes the test failure in TestDefaultNodeConfig.

Is this change intentional? If so, it should be documented as a breaking change in the release notes. Users upgrading to this version may experience different behavior if they rely on the default aggregator setting.


Below are two shell scripts to help verify the change in the default value of Aggregator and its impact on tests. The first script shows the surrounding context in pkg/config/defaults.go (including line 55), and the second searches for references to TestDefaultNodeConfig in the codebase so we can see what default value the tests expect.

Script 1: Show context of pkg/config/defaults.go around line 55

Script 2: Find references to TestDefaultNodeConfig in the repository

Once we have the output from these queries, we can better determine whether the change (from true to false) in the default value of Aggregator was intentional. If intentional, the breaking change must be clearly documented in the release notes to warn users of the changed behavior.


🏁 Script executed:

#!/bin/bash
# Display lines 50 to 60 from pkg/config/defaults.go for context.
sed -n '50,60p' pkg/config/defaults.go

Length of output: 480


🏁 Script executed:

#!/bin/bash
# Search for the TestDefaultNodeConfig reference to see what default value is expected.
rg "TestDefaultNodeConfig" -n .

Length of output: 227


Breaking Change: Default Aggregator Behavior

  • The code in pkg/config/defaults.go (line 55) now sets Aggregator to false.
  • The test TestDefaultNodeConfig (located in pkg/config/config_test.go) is failing—likely because it expects the default value to be true.
  • If this change to a default value of false is intentional, please update the release notes and tests accordingly to document the breaking change and ensure users are aware of the altered behavior.
  • If not intentional, consider reverting the default back to true or adjusting the test expectations.
node/node_integration_test.go (4)

21-21: Good addition of remote signer package import

Adding the import for the noop signer implementation is necessary for the integration test to use the new signer interface.


48-49: Good migration to signer interface

Creating a NoopSigner from the existing validator key properly implements the transition from directly using private keys to using the signer.Signer interface.


59-60: Good code cleanup

Reusing the existing err variable instead of redeclaring it improves code consistency.


68-68: Properly updated function parameter

Changing from passing genesisValidatorKey directly to passing the remoteSigner is consistent with the PR's goal of switching to the signer interface.

node/helpers_test.go (4)

16-16: Added import for the NoopSigner implementation.

This import adds the necessary functionality to use the NoopSigner implementation, aligning with the refactoring from direct crypto key usage to a signer interface pattern.


48-49: Implemented remote signer with proper error handling.

The code now creates a NoopSigner instead of directly using the crypto key, which is a good abstraction that allows for future flexibility with different signer implementations. The error handling is properly implemented with require.NoError.


56-57: Fixed error variable reuse.

The error handling now correctly reuses the existing err variable instead of redeclaring it, avoiding variable shadowing issues.


65-65: Updated function parameter to use the signer interface.

The node initialization now uses the remoteSigner interface instead of directly passing the private key, which aligns with the broader architectural shift toward abstraction of signing mechanisms.

node/full_node_integration_test.go (9)

20-20: Added import for NoopSigner implementation.

This import adds the necessary functionality to use the NoopSigner implementation across the integration tests.


66-67: Implemented remote signer in SetupTest with proper error handling.

The test setup now creates a NoopSigner instead of directly using the crypto key, with appropriate error handling via require.NoError.


74-75: Fixed error variable reuse in SetupTest.

The error handling now correctly reuses the existing err variable instead of redeclaring it, avoiding variable shadowing issues.


83-83: Updated NewNode parameter to use the signer interface in SetupTest.

The node initialization now correctly uses the remoteSigner interface instead of directly passing the private key.


320-321: Implemented remote signer in TestMaxPending with proper error handling.

The test now creates a NoopSigner instead of directly using the crypto key, with appropriate error handling.


328-329: Fixed error variable reuse in TestMaxPending.

The error handling now correctly reuses the existing err variable instead of redeclaring it.


337-337: Updated NewNode parameter to use the signer interface in TestMaxPending.

The node initialization now correctly uses the remoteSigner interface instead of directly passing the private key.


406-407: Implemented remote signer in TestStateRecovery with proper error handling.

The test now creates a NoopSigner instead of directly using the crypto key, with appropriate error handling.


420-420: Updated NewNode parameter to use the signer interface in TestStateRecovery.

The node initialization now correctly uses the remoteSigner interface instead of directly passing the private key.

buf.yaml (3)

1-1: Updated buf version to v2.

The buf tool configuration has been updated to use the newer v2 format, which is a necessary update to support the latest features and protocol buffer compilation mechanisms.


3-4: Restructured configuration with modules section.

The configuration now uses the modules-based approach instead of the older build section, which better aligns with buf v2's architecture. This change specifies the proto directory as the module path.


8-8: Added file naming convention rule.

The FILE_LOWER_SNAKE_CASE lint rule has been added, which enforces consistent file naming for protocol buffer files. This is a good practice that improves code organization.

sequencers/single/go.mod (1)

19-19:

Details

✅ Verification successful

Added direct dependency on google.golang.org/protobuf.

The project now directly depends on Google's official protobuf implementation rather than including it as an indirect dependency. This change aligns with the updated buf.yaml configuration and supports the shift to using protobuf-based signer implementations.


🏁 Script executed:

#!/bin/bash
# Verify if this protobuf package is being used in the codebase

# Check for imports of google.golang.org/protobuf in the repository
rg -l "google\.golang\.org/protobuf" --type go

Length of output: 472


Protobuf Direct Dependency Added and Verified

The direct dependency on google.golang.org/protobuf is indeed used throughout the codebase. Our verification confirms that this package is imported in multiple files (e.g., within types/serialization.go, types/pb/rollkit/v1/*.go, among others). This change aligns correctly with the updated buf.yaml configuration and supports the transition to protobuf-based signer implementations.

pkg/signer/noop/signer.go (3)

9-14: The NoopSigner struct looks good with appropriate fields

The structure properly implements the signer.Signer interface with the necessary fields to store private and public keys.


25-28: LGTM - Sign method properly delegates to the underlying key

The Sign method correctly implements the Signer interface by delegating to the private key's Sign method.


30-33: LGTM - GetPublic method implementation is clean

The GetPublic method correctly implements the Signer interface by returning the stored public key.

node/node_test.go (4)

23-23: LGTM - Import for noop signer added correctly

The import for the remote signer is added correctly, using a descriptive alias to distinguish it from other packages.


183-184: Proper initialization of the remote signer

The NoopSigner is properly created using the genesis validator key and tested for errors.


191-191: Good refactoring to avoid variable shadowing

Changed from using := to = to reuse the existing error variable instead of shadowing it.


202-202: Proper replacement of direct key usage with signer interface

The code now correctly uses the remoteSigner interface instead of directly passing the private key.

pkg/signer/file/example_test.go (2)

12-42: LGTM - Well-structured test for FileSystemSigner

The test thoroughly covers key generation, file creation, signing, and verification.


61-65: LGTM - Good error case testing

The test properly checks the behavior with an incorrect passphrase, ensuring robust error handling.

pkg/signer/noop/signer_test.go (3)

10-48: LGTM - Comprehensive test cases for the basic signer functionality

The tests cover creation, key retrieval, and signing/verification - all essential operations for a signer implementation.


50-74: LGTM - Good test for key uniqueness

This test ensures that different signer instances created with different private keys have unique public keys, which is an important security property.


76-95: LGTM - Well-designed negative test case

Testing that verification fails with an incorrect message is an important security check that demonstrates the signer behaves correctly in failure scenarios.

cmd/rollkit/commands/init.go (2)

11-11: LGTM: New import for file signer package.

Added import for the file signer package to support local file signing initialization.


107-110: LGTM: New flag for signer passphrase.

The initialization function adds a flag for the signer passphrase, which is required when using the local file signer.

pkg/config/config.go (4)

104-114: LGTM: New signer configuration flags.

Added appropriate constants for signer configuration flags with clear comments.


167-169: LGTM: Added signer field to Config struct.

The Config struct now includes a Signer field of type SignerConfig, properly annotated with mapstructure and yaml tags.


220-224: LGTM: New SignerConfig struct.

The SignerConfig struct is well-defined with appropriate fields and clear comments. It provides enough flexibility to support different signer types.


289-292: LGTM: Added signer flags to command.

The AddFlags function now includes the new signer configuration flags, properly initialized with default values.

node/node.go (3)

14-14: LGTM: Updated import to include signer package.

Replaced the crypto.PrivKey import with the new signer package import.


31-31: Good refactoring to use signer.Signer interface.

The parameter type has been changed from crypto.PrivKey to signer.Signer, enhancing modularity and flexibility by using an interface instead of a concrete type.


43-43: LGTM: Updated parameter name in function call.

The parameter name has been consistently updated from signingKey to signer in the newFullNode function call.

block/manager_test.go (9)

27-28: Add signer & no-op signer imports
These imports introduce the new abstract signer interface and the no-op implementation.


174-174: Initialize test payload
Defining a straightforward payload for signing tests. Looks fine.


178-180: Generate keypair and wrap in NoopSigner
Generating an Ed25519 keypair and instantiating a NoopSigner around it is consistent with the updated signing approach. Error handling is properly enforced.


183-186: Refactor test case to use signer
The table-driven test now uses a single signer field. This aligns well with the new interface-based design.


190-190: Assign signer to m.proposerKey
Replacing the direct private key assignment with a signer-based approach.


193-194: Public key retrieval and verification
The code correctly retrieves the public key from the signer and verifies the signature.


365-365: Update signerPrivKey to signer.Signer
Adopting the signer interface consistently in Test_isProposer.


380-381: Wrap generated key with NoopSigner
Again, the private key is wrapped with NoopSigner for testing. Error checks look good.


384-384: Include signer in args
Passing the signer further standardizes the updated interfaces.

block/manager.go (4)

28-28: Introduce signer import
Importing the signer package lays groundwork for using the abstract signer interface.


110-110: Replace proposerKey with signer.Signer
Using a signer field in the Manager struct decouples cryptographic details from direct private key usage.


224-224: Adjust NewManager to accept signer
Swapping out the private key parameter for a signer.Signer fosters a cleaner abstraction.


397-397: Stubbed isProposer function
This function unconditionally returns true, which may not be the final desired logic. Please verify that this placeholder is appropriate.

Would you like to confirm if a real proposer check is required?

node/full.go (3)

28-28: Add signer package import
Importing the signer interface for node usage.


71-71: Use signer.Signer in newFullNode
Replaces a private key parameter with the higher-level signer interface, simplifying key handling.


106-106: Forward signer to initBlockManager
Passing the signer object ensures all signing flows align with the new interface.

cmd/rollkit/commands/run_node.go (5)

26-27: Add signer & file-based signer imports
Bringing in the signer interface and file-based signer helps implement multiple signing modes.


59-66: Enforce passphrase for aggregator + file signer
Ensures aggregator nodes with a file-based signer specify a non-empty passphrase, preventing accidental misconfiguration.


70-70: Instantiate the direct KV executor
Sets up a local test executor for demonstration or development.


75-75: Log executor address
Provides debug information. This can be helpful in diagnosing runtime issues.


106-106: Pass signer to NewNode
Ensures that the node is constructed with the correct signing interface.

types/pb/rollkit/v1/v1connect/signer.connect.go (7)

1-20: All generated code for Connect appears standard and consistent.

The constant checks for Connect version compatibility and the package references look correct. No issues spotted here.


21-41: Service name constants and RPC procedure definitions are properly exposed.

They align well with the declared proto definitions.


42-48: Client interface and method signatures are clear and self-documenting.

No immediate concerns regarding parameter or return types. The design seems appropriately minimal.


50-75: Client factory function constructs separate clients for each RPC.

Everything looks properly trimmed and validated. The usage of reflection-based method schemas is an effective approach in Connect for strong RPC definitions.


76-91: Client method implementations delegate to connect.NewClient.

Calls appear straightforward. Returning the correct response types, with no extraneous logic.


92-129: Handler interface and HTTP handler construction logic are well-structured.

The multi-protocol support via Connect’s unary handlers with GCM support is standard. The switch-based dispatching on method paths is correct and easily maintainable.


131-141: Unimplemented handler ensures that unimplemented RPCs raise CodeUnimplemented.

This is standard for stubbed server implementations.

pkg/signer/file/local.go (12)

1-19: Struct and import organization look good.

The FileSystemSigner struct and concurrency primitives are logically placed. Sufficient external dependencies are imported for cryptographic operations.


20-28: Mutex usage approach is appropriate.

Using a read-write mutex for reading/writing keys appears consistent with the code’s locking logic.


29-36: Key data structure is adequately defined for on-disk storage.

The optional salt aligns with backward-compatibility needs.


37-65: Key generation and initial storage logic is well-organized.

  1. The code creates a directory if none exists and correctly sets secure permissions.
  2. Generating a new key if the file does not exist is a sensible default.
  3. Wiping passphrase memory afterward is a best-effort approach given Go’s garbage collection limitations.

91-117: Secure key handling logic is robust; Argon2 with random salt is recommended.

  1. Storing the salt and ephemeral data in JSON with restricted file permissions (0600) is good.
  2. Carefully zeroing passphrase and derived keys is an additional layer of security.

131-141: Key file load approach is consistent with the save logic.

You properly unmarshal JSON, handle backward compatibility for missing salts, and zero out sensitive data.


142-169: AES-GCM usage is correct.

Nonce generation is performed from a secure random source. Good job ensuring no encryption re-use occurs.


220-235: Raw key unmarshaling for Ed25519 is straightforward.

The code sets private and public keys in memory and zeroes out ephemeral data.


237-247: Signing logic aligns with the Signer interface.

Returning an error if privateKey is nil is a good guard.


249-259: Public key retrieval is consistent.

Again, a nil-check is in place. This ensures correct usage.


261-269: Argon2 parameters are in a reasonable range for security.

32MB memory might be large for constrained environments but is a good default for desktop/server usage.


286-291: Memory zeroing is an excellent extra layer, though not fully guaranteed in Go.

Still a good practice for limiting exposure in memory.

Comment on lines +1 to +31
syntax = "proto3";

package rollkit.v1;

option go_package = "github.com/rollkit/rollkit/types/pb/rollkit/v1";

// The SignRequest holds the bytes we want to sign.
message SignRequest {
bytes message = 1;
}

// The SignResponse returns the signature bytes.
message SignResponse {
bytes signature = 1;
}

// The GetPublicRequest is an empty request.
message GetPublicRequest {}

// The GetPublicResponse returns the public key.
message GetPublicResponse {
bytes public_key = 1;
}

// The SignerService defines the RPCs to sign and to retrieve the public key.
service SignerService {
// Sign signs the given message.
rpc Sign(SignRequest) returns (SignResponse);
// GetPublic returns the public key.
rpc GetPublic(GetPublicRequest) returns (GetPublicResponse);
} No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Good protocol definition, but missing a newline at the end of file.

The protocol definition for the signer service is well-structured with clear documentation for each message and RPC method. The service provides the essential functionality needed for remote signing.

However, there's a pipeline failure indicating a missing newline at the end of the file.

service SignerService {
  // Sign signs the given message.
  rpc Sign(SignRequest) returns (SignResponse);
  // GetPublic returns the public key.
  rpc GetPublic(GetPublicRequest) returns (GetPublicResponse);
}
+
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
syntax = "proto3";
package rollkit.v1;
option go_package = "github.com/rollkit/rollkit/types/pb/rollkit/v1";
// The SignRequest holds the bytes we want to sign.
message SignRequest {
bytes message = 1;
}
// The SignResponse returns the signature bytes.
message SignResponse {
bytes signature = 1;
}
// The GetPublicRequest is an empty request.
message GetPublicRequest {}
// The GetPublicResponse returns the public key.
message GetPublicResponse {
bytes public_key = 1;
}
// The SignerService defines the RPCs to sign and to retrieve the public key.
service SignerService {
// Sign signs the given message.
rpc Sign(SignRequest) returns (SignResponse);
// GetPublic returns the public key.
rpc GetPublic(GetPublicRequest) returns (GetPublicResponse);
}
syntax = "proto3";
package rollkit.v1;
option go_package = "github.com/rollkit/rollkit/types/pb/rollkit/v1";
// The SignRequest holds the bytes we want to sign.
message SignRequest {
bytes message = 1;
}
// The SignResponse returns the signature bytes.
message SignResponse {
bytes signature = 1;
}
// The GetPublicRequest is an empty request.
message GetPublicRequest {}
// The GetPublicResponse returns the public key.
message GetPublicResponse {
bytes public_key = 1;
}
// The SignerService defines the RPCs to sign and to retrieve the public key.
service SignerService {
// Sign signs the given message.
rpc Sign(SignRequest) returns (SignResponse);
// GetPublic returns the public key.
rpc GetPublic(GetPublicRequest) returns (GetPublicResponse);
}
🧰 Tools
🪛 GitHub Actions: CI and Release

[error] 29-29: Format diff -1/+1. The file is missing a newline at the end of the file.

@gupadhyaya gupadhyaya self-requested a review March 31, 2025 15:28
Copy link
Contributor

@facundomedica facundomedica left a comment

Choose a reason for hiding this comment

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

LGTM (ut)

@tac0turtle tac0turtle merged commit b151c8b into feature/exec_api Mar 31, 2025
17 of 24 checks passed
@tac0turtle tac0turtle deleted the marko/remote_signer branch March 31, 2025 20:17
@github-project-automation github-project-automation bot moved this to Done in Evolve Mar 31, 2025
@tac0turtle tac0turtle removed this from Evolve Apr 24, 2025
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.

4 participants