Skip to content

Conversation

@agaffney
Copy link
Contributor

@agaffney agaffney commented Nov 13, 2025

Summary by CodeRabbit

  • New Features

    • Peers can request and receive cryptographic proofs by name and root hash via a new public GetProof operation.
    • The messaging protocol now includes proof-request and proof-response types, decodes embedded proofs, and validates response types and payloads.
  • Tests

    • Added an encode/decode round-trip test covering the new proof-request message.

@agaffney agaffney requested a review from a team as a code owner November 13, 2025 13:40
@coderabbitai
Copy link

coderabbitai bot commented Nov 13, 2025

📝 Walkthrough

Walkthrough

The diff adds MsgGetProof (Root, Key) with Encode/Decode and extends MsgProof to include Root, Key and a *handshake.Proof plus Encode/Decode. decodeMessage now recognizes MessageGetProof and MessageProof and uses the new types. Peer.GetProof(name, rootHash) was added: it derives Key = sha3.Sum256(name), sends MsgGetProof, awaits a response, asserts it is a MsgProof, and returns the embedded Proof. A unit test was added for MsgGetProof encode/decode round-trip.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify MsgGetProof.Encode/Decode enforce exact 64-byte layout and correct endianness/ordering.
  • Check MsgProof.Decode for proper minimum-length checks and correct delegation to handshake.Proof decoding.
  • Review Peer.GetProof: sha3.Sum256 usage, message send/receive sequencing, type assertion error paths, and error messages.
  • Confirm tests (TestMsgGetProofEncodeDecode) use representative vectors and re-encode matches original.

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding support for getting name proofs from Handshake peers via the new GetProof method.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/handshake-get-proof

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

@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: 1

🧹 Nitpick comments (2)
internal/handshake/protocol/peer.go (1)

220-240: Remove redundant type conversion.

The implementation correctly computes the SHA3-256 hash and handles the request/response flow. However, Line 225 has a redundant type conversion: sha3.Sum256 already returns [32]byte, so the explicit [32]byte(key) cast is unnecessary.

Apply this diff to simplify:

 	key := sha3.Sum256([]byte(name))
 	getProofMsg := &MsgGetProof{
 		Root: rootHash,
-		Key:  [32]byte(key),
+		Key:  key,
 	}
internal/handshake/protocol/messages.go (1)

447-450: Clarify the intentional receive-only design of MsgProof.

Verification confirms MsgProof is receive-only in this implementation—it's only populated via Decode() when receiving protocol messages (peer.go:235), never sent via Encode(). The suggested documentation update improves clarity for future maintainers:

 func (m *MsgProof) Encode() []byte {
-	// NOTE: this is not implemented because proof encoding is not implemented
+	// NOTE: MsgProof is only received, never sent. Encoding is intentionally unimplemented.
+	// If sending proofs becomes necessary, implement handshake.Proof.Encode() first.
 	return []byte{}
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c97e646 and c102df4.

📒 Files selected for processing (2)
  • internal/handshake/protocol/messages.go (2 hunks)
  • internal/handshake/protocol/peer.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
internal/handshake/protocol/peer.go (2)
internal/handshake/spv.go (1)
  • Proof (63-74)
internal/handshake/protocol/messages.go (3)
  • MsgGetProof (420-423)
  • MessageGetProof (31-31)
  • MsgProof (441-445)
internal/handshake/protocol/messages.go (1)
internal/handshake/spv.go (1)
  • Proof (63-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (go)
🔇 Additional comments (3)
internal/handshake/protocol/messages.go (2)

86-89: LGTM! Message routing correctly added.

The decoder routing for GetProof and Proof messages follows the established pattern and integrates cleanly with existing message types.


420-439: LGTM! Well-structured encoding/decoding implementation.

The MsgGetProof implementation correctly validates payload length and handles the Root and Key fields symmetrically.

internal/handshake/protocol/peer.go (1)

11-11: LGTM! Import correctly added.

The crypto/sha3 import is necessary for computing the name hash in the GetProof method.

@agaffney agaffney force-pushed the feat/handshake-get-proof branch 2 times, most recently from c74b780 to 0cc8dbf Compare November 13, 2025 16:02
Signed-off-by: Aurora Gaffney <aurora@blinklabs.io>
@agaffney agaffney force-pushed the feat/handshake-get-proof branch from 0cc8dbf to a925341 Compare November 13, 2025 16:09
Copy link

@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: 1

🧹 Nitpick comments (1)
internal/handshake/protocol/messages.go (1)

447-450: Consider documenting or enforcing the Encode limitation.

The Encode method returns an empty byte slice with a comment noting it's not implemented. While this may be intentional (if MsgProof is only received and never sent), it could lead to subtle bugs if someone attempts to send a MsgProof message.

Consider one of these approaches:

Option 1: Add a panic to make the limitation explicit

 func (m *MsgProof) Encode() []byte {
-	// NOTE: this is not implemented because proof encoding is not implemented
-	return []byte{}
+	// MsgProof encoding is not supported; this message is only received, not sent
+	panic("MsgProof.Encode is not implemented")
 }

Option 2: Add a TODO if this should be implemented later

 func (m *MsgProof) Encode() []byte {
-	// NOTE: this is not implemented because proof encoding is not implemented
+	// TODO: Implement proof encoding to support sending MsgProof messages
 	return []byte{}
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c102df4 and a925341.

📒 Files selected for processing (3)
  • internal/handshake/protocol/messages.go (2 hunks)
  • internal/handshake/protocol/messages_test.go (1 hunks)
  • internal/handshake/protocol/peer.go (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • internal/handshake/protocol/messages_test.go
🧰 Additional context used
🧬 Code graph analysis (2)
internal/handshake/protocol/peer.go (2)
internal/handshake/spv.go (1)
  • Proof (63-74)
internal/handshake/protocol/messages.go (3)
  • MsgGetProof (420-423)
  • MessageGetProof (31-31)
  • MsgProof (441-445)
internal/handshake/protocol/messages.go (1)
internal/handshake/spv.go (1)
  • Proof (63-74)
🔇 Additional comments (6)
internal/handshake/protocol/peer.go (2)

11-11: LGTM: Standard library import for SHA3 hashing.

The addition of crypto/sha3 is appropriate for computing the key hash in the GetProof method.


222-222: Verify domain name normalization requirements against Handshake protocol specification.

The review concern is valid: domain names hashed without normalization would produce different keys for equivalent domains (e.g., "Example.com" vs "example.com"), breaking Merkle tree lookups. The codebase shows normalization patterns elsewhere (hashes normalized in genesis.go and network.go), yet no domain normalization occurs in GetProof() at line 222.

However, I cannot definitively determine whether this requires fixing because:

  • GetProof has no existing callers in the codebase (new API)
  • No protocol documentation found specifying whether domain names should be normalized before hashing
  • No domain normalization functions exist in the codebase to indicate expected behavior

Verify the Handshake protocol specification to confirm:

  1. Whether domain names must be normalized (lowercase, punycode encoding) before hashing
  2. Whether normalization responsibility belongs in GetProof() or at the caller level
  3. Test with case-varied and international domain names to ensure correct behavior
internal/handshake/protocol/messages.go (4)

31-32: LGTM: Message type constants follow existing conventions.

The new message type constants are properly defined and don't conflict with existing values.


86-89: LGTM: decodeMessage cases follow existing pattern.

The new message type cases are correctly integrated into the decode switch statement.


420-439: LGTM: MsgGetProof implementation is correct.

The struct definition and encode/decode methods are well-implemented with proper length validation to prevent panics.


452-465: LGTM: MsgProof.Decode properly validates and decodes.

The decode method correctly validates the minimum payload length (addressing the previous review comment), extracts Root and Key fields, and delegates Proof decoding to the handshake.Proof.Decode method.

Comment on lines +220 to +240
// GetProof requests a proof for a domain name from the network peer
func (p *Peer) GetProof(name string, rootHash [32]byte) (*handshake.Proof, error) {
key := sha3.Sum256([]byte(name))
getProofMsg := &MsgGetProof{
Root: rootHash,
Key: key,
}
if err := p.sendMessage(MessageGetProof, getProofMsg); err != nil {
return nil, err
}
// Wait for Proof response
msg, err := p.receiveMessage()
if err != nil {
return nil, err
}
msgProof, ok := msg.(*MsgProof)
if !ok {
return nil, fmt.Errorf("unexpected message: %T", msg)
}
return msgProof.Proof, nil
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate response Root and Key match the request.

The method doesn't verify that the returned MsgProof contains the same Root and Key that were requested. A malicious or buggy peer could return a proof for a different domain name or tree root, which would be accepted without validation. This could lead to incorrect proof verification or security vulnerabilities.

Apply this diff to add validation:

 func (p *Peer) GetProof(name string, rootHash [32]byte) (*handshake.Proof, error) {
 	key := sha3.Sum256([]byte(name))
 	getProofMsg := &MsgGetProof{
 		Root: rootHash,
 		Key:  key,
 	}
 	if err := p.sendMessage(MessageGetProof, getProofMsg); err != nil {
 		return nil, err
 	}
 	// Wait for Proof response
 	msg, err := p.receiveMessage()
 	if err != nil {
 		return nil, err
 	}
 	msgProof, ok := msg.(*MsgProof)
 	if !ok {
 		return nil, fmt.Errorf("unexpected message: %T", msg)
 	}
+	if msgProof.Root != rootHash {
+		return nil, errors.New("proof root hash mismatch")
+	}
+	if msgProof.Key != key {
+		return nil, errors.New("proof key mismatch")
+	}
 	return msgProof.Proof, nil
 }
🤖 Prompt for AI Agents
internal/handshake/protocol/peer.go around lines 220 to 240: after receiving and
type-asserting the MsgProof, verify that msgProof.Root equals the requested
rootHash and msgProof.Key equals the requested key (sha3.Sum256([]byte(name)));
if either comparison fails, return a descriptive error (e.g., "proof root
mismatch" or "proof key mismatch" including expected vs actual) instead of
accepting the proof, otherwise return msgProof.Proof as before.

@agaffney agaffney merged commit 5480036 into main Nov 17, 2025
11 checks passed
@agaffney agaffney deleted the feat/handshake-get-proof branch November 17, 2025 13:00
@agaffney agaffney linked an issue Nov 17, 2025 that may be closed by this pull request
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.

Develop network protocol code for Handshake

3 participants