Checked decoding changes buffer bytes after the returned length
Description
Checked DecodeBuilder::onto modifies bytes after the returned payload length.
Steps to Reproduce
With bs58 0.5.1 and the check feature enabled, run this example. Its success reproduces the discrepancy:
let encoded = bs58::encode([42]).with_check().into_string();
let mut output = [0xa5; 16];
let len = bs58::decode(encoded).with_check(None).onto(&mut output).unwrap();
assert_eq!(len, 1);
assert_eq!(&output[..5], &[42, 255, 18, 44, 14]);
assert_eq!(&output[5..], &[0xa5; 11]);
Expected Behavior
DecodeBuilder::onto documents the return value as the length written and promises not to touch bytes after the decoded output.
Actual Behavior
Checked decoding writes the four checksum bytes after the payload and then returns only the payload length. The same behavior occurs with cb58; a buffer large enough for just the returned payload is rejected as too small. The demonstrated writes are within the supplied buffer.
Environment
bs58 0.5.1 with check; the analogous path uses cb58.
Additional Context
See upstream issue #133.
Change history
- v1 · created · 2026-11-03 03:48 UTC
{ "title": "Checked decoding changes buffer bytes after the returned length", "body": "## Description\n\nChecked `DecodeBuilder::onto` modifies bytes after the returned payload length.\n\n## Steps to Reproduce\n\nWith bs58 0.5.1 and the `check` feature enabled, run this example. Its success reproduces the discrepancy:\n\n```rust\nlet encoded = bs58::encode([42]).with_check().into_string();\nlet mut output = [0xa5; 16];\nlet len = bs58::decode(encoded).with_check(None).onto(&mut output).unwrap();\nassert_eq!(len, 1);\nassert_eq!(&output[..5], &[42, 255, 18, 44, 14]);\nassert_eq!(&output[5..], &[0xa5; 11]);\n```\n\n## Expected Behavior\n\n`DecodeBuilder::onto` documents the return value as the length written and promises not to touch bytes after the decoded output.\n\n## Actual Behavior\n\nChecked decoding writes the four checksum bytes after the payload and then returns only the payload length. The same behavior occurs with `cb58`; a buffer large enough for just the returned payload is rejected as too small. The demonstrated writes are within the supplied buffer.\n\n## Environment\n\nbs58 0.5.1 with `check`; the analogous path uses `cb58`.\n\n## Additional Context\n\nSee [upstream issue #133](https://github.com/Nullus157/bs58-rs/issues/133).", "validity": "reported", "upstream_status": "not_reported" } - v2 · link_added · 2026-11-03 03:51 UTC
{ "id": "97e7adeb-d6d5-4843-ac87-73c74a2594c3", "kind": "issue", "url": "https://github.com/Nullus157/bs58-rs/issues/133", "edit_version": 1 } - v3 · edited · 2026-11-03 03:51 UTC
{ "evidence_url": "https://github.com/MasWag/crate-proofs/blob/1c8a2741db2110c65d2457d36723612560bbe5f4/bs58/0.5.1/evidence/reproduce-findings/src/main.rs", "upstream_status": "reported_upstream", "edit_version": 2 }