feat: add base16.decode_strict for canonical-form hex verification - #90
Conversation
Mirrors the existing decode_strict pattern on base32/rfc4648 and
base64/standard. Returns Error(NonCanonical) when input decodes
successfully but is not byte-equal to encode/1's output — i.e.
lowercase, mixed case, or any deviation from RFC 4648 §8's
uppercase canonical form.
Useful for HMAC/TOTP/WebAuthn/content-addressable-storage contexts
where the encoded string itself is part of the contract and two
distinct wire forms ("DEADBEEF" vs "deadbeef") for the same bytes
are a replay-attack surface that strict mode is meant to close.
The lenient decode/1 path is unchanged — it still accepts both
cases for the wide-tolerance read side.
Adds 6 regression tests covering uppercase canonical, lowercase
rejection, mixed case rejection, InvalidCharacter pass-through,
InvalidLength pass-through, and the empty-input case.
Closes #87
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdds a strict decoder ChangesBase16 Strict Decoder Implementation
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 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 |
Summary
Adds `base16.decode_strict/1` to close the API symmetry gap with
`base32/rfc4648` and `base64/standard`, both of which already
expose `decode_strict`.
Changes
in `src/yabase/base16.gleam`.
Design decisions
`encode_lowercase/1` is the documented opt-in non-canonical form,
so `decode_strict` rejects its output even though the lenient
`decode/1` accepts it. This matches the contract the package
already advertises in `encode/1`'s docstring.
`base32/rfc4648.decode_strict`: the canonicality check is
byte-equal (`encode(bytes) == input`). No `string.uppercase` or
other normalization step — that is exactly the bug base32/rfc4648.decode_strict accepts lowercase input — canonical-form contract violated (RFC 4648 §3.5/§6) #86 closed,
and reintroducing it here would defeat the purpose.
accepts both cases per the existing "the decoder remains
case-insensitive" contract noted in the module-level docstring.
Verification
Closes #87
Summary by CodeRabbit
New Features
Tests
Documentation