fix: handle hex string signatures and OverflowError in is_valid_message#944
fix: handle hex string signatures and OverflowError in is_valid_message#944m1lestones wants to merge 3 commits intoXRPLF:mainfrom
Conversation
Both `dir_root` and `owner` were marked as REQUIRED in the Directory model, but the XRPL ledger_entry API only requires one of the two. This caused a spurious XRPLModelException when constructing a Directory with only `owner` (a valid and commonly used pattern). - Make both `owner` and `dir_root` Optional[str] = None - Add _get_errors validation ensuring at least one is provided - Add regression tests covering owner-only, dir_root-only, and neither-provided cases Fixes XRPLF#885
sign() returns a hex-encoded string, but is_valid_message() expected raw bytes. Passing the hex string directly — or calling .encode() on it — produced a cryptic OverflowError from ecpy's EdDSA verifier instead of a clean False or a helpful exception. Two complementary fixes: - main.py: accept Union[str, bytes] for the signature parameter and auto-convert hex strings with bytes.fromhex(), matching the same pattern already used in sign() for the message parameter - ed25519.py: wrap _SIGNER.verify() in try/except (OverflowError, ValueError) and return False so malformed signatures never surface as an unhandled exception regardless of caller input Adds two regression tests: - hex string returned by sign() is accepted directly by is_valid_message - malformed bytes return False instead of raising OverflowError Fixes XRPLF#861
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 17 minutes and 20 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
WalkthroughThis PR addresses issue Changes
Possibly related issues
Poem
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (2 warnings, 1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
tests/unit/core/keypairs/test_main.py (1)
237-242: Consider adding test coverage for additional edge cases.The current test covers malformed bytes passed as signature. Consider adding tests for:
Invalid hex string — verifies behavior when a non-hex string like
"not-valid-hex"is passed as signature (this would currently raiseValueErrorper my earlier comment).secp256k1 malformed signature — verifies consistent behavior across both crypto backends (currently secp256k1 lacks the exception handling).
Suggested additional test
def test_is_valid_message_invalid_hex_string_signature(self): # Non-hex string should return False (or raise clear exception), not crash public_key = "ED01FA53FA5A7E77798F882ECE20B1ABC00BB358A9E55A202D0D0676BD0CE37A63" invalid_hex = "not-valid-hex" # This test will fail until main.py handles ValueError from bytes.fromhex() self.assertFalse(keypairs.is_valid_message(b"test message", invalid_hex, public_key))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/unit/core/keypairs/test_main.py` around lines 237 - 242, The is_valid_message path currently lets non-hex signatures and malformed secp256k1 signatures raise (e.g., ValueError from bytes.fromhex or backend-specific exceptions); update keypairs.is_valid_message to defensively parse the signature inside a try/except and to return False on bytes.fromhex ValueError/TypeError and on verification exceptions (e.g., OverflowError or the secp256k1 library's signature errors) rather than letting them propagate; ensure both Ed25519 and secp256k1 verification branches are wrapped so malformed hex and malformed signature bytes both yield False; add unit tests mirroring the provided malformed-sig test: one for a non-hex string signature and one for a secp256k1 malformed signature to assert False.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@xrpl/core/keypairs/ed25519.py`:
- Around line 92-95: The SECP256K1.is_valid_message method must mirror the
Ed25519 behavior: wrap the verification call in a try/except that catches
OverflowError and ValueError and returns False on those exceptions so the method
always returns a bool. Locate SECP256K1.is_valid_message and the call to the
secp verification routine (the code that currently performs the verify and can
raise) and add the same try/except pattern used in ed25519.is_valid_message to
return False for OverflowError and ValueError.
In `@xrpl/core/keypairs/main.py`:
- Around line 141-142: The conversion bytes.fromhex(signature) can raise
ValueError for invalid hex strings; wrap that conversion in a try/except
ValueError inside the function that handles signature verification (where the
local variable signature is converted) and return False for malformed hex inputs
to match the ed25519.py behavior; ensure the except only catches ValueError from
bytes.fromhex and does not swallow other exceptions, keeping the rest of the
verification flow unchanged.
---
Nitpick comments:
In `@tests/unit/core/keypairs/test_main.py`:
- Around line 237-242: The is_valid_message path currently lets non-hex
signatures and malformed secp256k1 signatures raise (e.g., ValueError from
bytes.fromhex or backend-specific exceptions); update keypairs.is_valid_message
to defensively parse the signature inside a try/except and to return False on
bytes.fromhex ValueError/TypeError and on verification exceptions (e.g.,
OverflowError or the secp256k1 library's signature errors) rather than letting
them propagate; ensure both Ed25519 and secp256k1 verification branches are
wrapped so malformed hex and malformed signature bytes both yield False; add
unit tests mirroring the provided malformed-sig test: one for a non-hex string
signature and one for a secp256k1 malformed signature to assert False.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: de1fc31d-64c9-48e9-8f34-d92075480db0
📒 Files selected for processing (5)
tests/unit/core/keypairs/test_main.pytests/unit/models/requests/test_ledger_entry.pyxrpl/core/keypairs/ed25519.pyxrpl/core/keypairs/main.pyxrpl/models/requests/ledger_entry.py
- Wrap bytes.fromhex(signature) in try/except ValueError in main.py so invalid hex strings return False instead of raising - Add AssertionError to ed25519.py exception handling to cover ecpy's internal assertion failures on malformed signatures - Add try/except (OverflowError, ValueError) to SECP256K1.is_valid_message to match ed25519 behavior - Add tests: invalid hex string signature and secp256k1 malformed signature Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Description
Fixes #861.
sign()returns a hex-encoded uppercase string.is_valid_message()expected raw bytes. Passing the hex string directly — or calling.encode()on it as a first-time user might — caused a crypticOverflowErrorfrom ecpy's internal EdDSA verifier instead of returningFalseor raising a descriptive exception.The natural usage pattern:
...raised an unhandled exception rather than working as expected.
Changes
xrpl/core/keypairs/main.pyis_valid_messagesignature changed fromsignature: bytes→signature: Union[str, bytes]stris passed, it is decoded withbytes.fromhex()before being forwarded — matching the same patternsign()already uses for themessageparameterxrpl/core/keypairs/ed25519.py_SIGNER.verify()intry/except (OverflowError, ValueError)returningFalsetests/unit/core/keypairs/test_main.pytest_is_valid_message_ed25519_hex_string_signature— the exact pattern from OverflowError exception when verifying a signed message #861:sign()output passed directly tois_valid_message()test_is_valid_message_ed25519_malformed_sig_returns_false— confirmsOverflowErroris caught and returnsFalseTest plan
test_is_valid_message_ed25519_hex_string_signaturepasses — hex string accepted directlytest_is_valid_message_ed25519_malformed_sig_returns_falsepasses — no OverflowErrorTestMaintests continue to pass