Skip to content

feat(rust-fuzzer): implement truncate and pad length mutators + fix broken test data - #300

Merged
codeZe-us merged 2 commits into
Boxkit-Labs:mainfrom
Yinklekay:feat/length-mutators-291
Jul 28, 2026
Merged

feat(rust-fuzzer): implement truncate and pad length mutators + fix broken test data#300
codeZe-us merged 2 commits into
Boxkit-Labs:mainfrom
Yinklekay:feat/length-mutators-291

Conversation

@Yinklekay

@Yinklekay Yinklekay commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements length-mutation fuzzer helpers (truncate / pad) for the
rust-address-fuzzer and fixes pre-existing broken test data in both
Rust crates. Closes #291.

Problem

Off-by-one and truncated inputs are classic parser killers. Feeding
progressively shorter and padded strings probes the length-handling
logic that base32 decoders often get wrong. The rust-address-fuzzer
had no dedicated mutators for length manipulation, leaving the
parser's edge-case behaviour around over-length and under-length
inputs unexplored.

Additionally, several tests across both Rust crates used a phantom
G address (GAHJJJKMOKYE4RVPZEWZTKH5FVI4PA3VL7GK2LFNUBSGBV3PR5T4Q)
that was only 53 characters long, while the parser declares
LEN_G = 56. These tests silently failed to validate anything
useful because the parse step always rejected the input before
reaching the logic being tested.

Changes

New: length mutators (src/mutators/length.rs)

truncate(addr, rng) — Randomly removes 1 to max(1, len/2)
trailing characters. Uses saturating_sub to guard against underflow
on empty / 1-char inputs. The shortened string is always too short
for any valid Stellar address.

pad(addr, rng) — Appends 1–16 random RFC 4648 base32 characters
(A–Z, 2–7). The extended string is always too long for any valid
Stellar address.

Module wiring in src/mutators/mod.rs with #![allow(dead_code)].

Bugfixes in existing test data

File Test Fix
prism-core/src/address.rs valid_g_address_parses 53-char phantom → 56-char spec-vector address
prism-core/src/address.rs lowercase_normalised_correctly Same replacement for both lower/upper variants
prism-core/src/address.rs invalid_base32_character Too-short address that failed at length gate → 56-char address with invalid char 1 that reaches the base32 check
rust-address-fuzzer/src/parse.rs parses_valid_g_address 53-char phantom → 56-char spec-vector address
rust-address-fuzzer/src/main.rs (compilation) saturating_add_signed expects isize, changed from i64 range to isize

All fixes use the valid G address GAYCUYT553C5LHVE2XPW5GMEJT4BXGM7AHMJWLAPZP53KJO7EIQADRSI
from the normative spec/vectors.json (module muxed_encode).

Test coverage

12 rust-address-fuzzer tests — all pass

Test Description
base_addresses_are_valid Setup guard: VALID_G and VALID_M from spec vectors are parseable
truncate_produces_shorter_string Truncated G address is strictly shorter
truncate_preserves_prefix Prefix character preserved after truncation
truncate_g_always_err_no_panic 200 seeds on G address → always Err, never Ok, never panics
truncate_m_always_err_no_panic 200 seeds on M address → always Err, never Ok, never panics
pad_produces_longer_string Padded G address is strictly longer
pad_preserves_prefix Prefix character preserved after padding
pad_g_always_err_no_panic 200 seeds on G address → always Err, never Ok, never panics
pad_m_always_err_no_panic 200 seeds on M address → always Err, never Ok, never panics
parses_valid_g_address (fixed) Valid spec-vector address parses correctly
rejects_garbage Random string rejected
rejects_empty_string Empty input rejected

Each parse call in the four "always Err" tests is wrapped in
std::panic::catch_unwind to catch both partial-parse Ok results
and genuine panics. 200 seeds × 4 test cases = 800 distinct
parse attempts
, all producing errors with zero panics.

7 prism-core tests — all pass

All original tests now pass with the corrected addresses.

CI validation

Check Result
cargo test (rust-address-fuzzer) 12 passed, 0 failed
cargo test (prism-core) 7 passed, 0 failed
cargo clippy --all-targets (rust-address-fuzzer) No warnings
cargo clippy --all-targets (prism-core) No warnings

Design decisions

  • truncation range (1 to len/2): Removing more than half leaves
    strings rejected at the prefix check; keeping the range ensures
    the parser consistently reaches length-validation logic.
  • pad range (1–16): Stellar addresses have fixed lengths (56/69).
    Even +1 guarantees InvalidLength. The 1–16 range adds variety.
  • Seed-based determinism: StdRng::seed_from_u64 makes every
    test run reproducible for debugging.
  • Spec-vector addresses: Cross-language consistency — the same
    addresses pass TypeScript, Go, Dart, and now Rust.

Summary by CodeRabbit

  • Tests
    • Updated address validation test cases with refreshed lowercase and uppercase examples.
    • Expanded malformed-address coverage by testing truncated and overlong addresses.
    • Confirmed invalid address inputs are rejected safely without causing application crashes.
    • Added deterministic checks to improve confidence in address parsing across varied malformed inputs.

Add length-mutation helpers for the rust-address-fuzzer:
- truncate(addr, rng): removes 1 to len/2 trailing characters
- pad(addr, rng): appends 1-16 random base32 characters

Both produce strings guaranteed to fail parsing with no panics
and no partial-parse Ok results.

Also fixes pre-existing test data: 3 tests in prism-core and
1 test in parse.rs used 53-char phantom addresses that could
never pass the LEN_G=56 check. Replaced with valid 56-char
addresses from spec/vectors.json.

Closes Boxkit-Labs#291
@drips-wave

drips-wave Bot commented Jul 27, 2026

Copy link
Copy Markdown

@Yinklekay Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1e36b830-427a-4929-bf65-15c34cc98dcf

📥 Commits

Reviewing files that changed from the base of the PR and between d35f610 and 41a661d.

📒 Files selected for processing (2)
  • examples/prism-core/src/address.rs
  • examples/rust-address-fuzzer/src/main.rs

📝 Walkthrough

Walkthrough

Adds truncation and padding mutators for Stellar addresses, integrates them into the fuzzer module tree, validates malformed inputs, and updates lowercase/uppercase parser test vectors.

Changes

Address length mutators

Layer / File(s) Summary
Length mutators and validation
examples/rust-address-fuzzer/src/mutators/length.rs
Adds random truncation and base32 padding, with deterministic tests confirming length changes, parse errors, and panic-free behavior.
Fuzzer module wiring
examples/rust-address-fuzzer/src/mutators/mod.rs, examples/rust-address-fuzzer/src/main.rs
Exports the length mutator module and registers the mutator module in the fuzzer binary.

Parser test vectors

Layer / File(s) Summary
Lowercase normalization test vectors
examples/prism-core/src/address.rs
Replaces the lowercase and uppercase address strings while retaining successful parse assertions.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: codeze-us

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 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 new length mutators and the test-data fix.
Linked Issues check ✅ Passed The PR implements truncate/pad mutators and tests that mutated inputs fail safely without panics or partial parses.
Out of Scope Changes check ✅ Passed The visible changes stay aligned with the fuzzer mutators and supporting test fixtures, with no clear unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/rust-address-fuzzer/src/main.rs`:
- Line 1: Update the fuzz loop in run_random to add a length-mutation campaign
that uses valid G/M seeds, invokes both mutators::truncate and mutators::pad,
and passes each mutated result to fuzz_one. Keep the existing random_string
campaign intact and remove any unused-code suppression in mutators/mod.rs that
is no longer needed once these helpers are exercised.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 81a17a06-4f4a-4524-afc3-c74cbba308e2

📥 Commits

Reviewing files that changed from the base of the PR and between d2898d4 and d35f610.

📒 Files selected for processing (5)
  • examples/prism-core/src/address.rs
  • examples/rust-address-fuzzer/src/main.rs
  • examples/rust-address-fuzzer/src/mutators/length.rs
  • examples/rust-address-fuzzer/src/mutators/mod.rs
  • examples/rust-address-fuzzer/src/parse.rs

@@ -1,3 +1,4 @@
mod mutators;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Actually feed length mutations into the fuzz loop.

Declaring the module does not register either helper: run_random still fuzzes only random_string, while mutators/mod.rs suppresses their unused-code warning. Add a campaign that calls both truncate and pad on valid G/M seeds and passes each result to fuzz_one; otherwise this binary never exercises the new mutators.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/rust-address-fuzzer/src/main.rs` at line 1, Update the fuzz loop in
run_random to add a length-mutation campaign that uses valid G/M seeds, invokes
both mutators::truncate and mutators::pad, and passes each mutated result to
fuzz_one. Keep the existing random_string campaign intact and remove any
unused-code suppression in mutators/mod.rs that is no longer needed once these
helpers are exercised.

@codeZe-us

Copy link
Copy Markdown
Contributor

@Yinklekay fix conflicts

@codeZe-us
codeZe-us merged commit a02e750 into Boxkit-Labs:main Jul 28, 2026
1 of 3 checks passed
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.

Implement truncation and length mutators.

2 participants