You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When encode is applied to a HumanReadablePart containing one or more upper-case characters, it results in an invalid Bech32 string that cannot be decoded with the decode function.
> encode lower memptyRight"test12hrzfj"> encode upper memptyRight"test12hrzfj"-- SAME
# Should give the same output:
> decode $ fromRight undefined$ encode lower memptyRight (HumanReadablePart"test","")
> decode $ fromRight undefined$ encode upper memptyRight (HumanReadablePart"test","") -- SUCCESS
Actual behaviour
# Should give the same output:
> encode lower memptyRight"test12hrzfj"> encode upper memptyRight"test13jgcyw"-- DIFFERENT
# Should give the same output:
> decode $ fromRight undefined$ encode lower memptyRight (HumanReadablePart"test","")
> decode $ fromRight undefined$ encode upper memptyLeft (StringToDecodeContainsInvalidChars[]) -- FAILURE
Cause
This appears to be caused by the encode function. Internally, it calculates a checksum based on the supplied HumanReadablePart, which can be upper or lower case (or mixed case). Unfortunately, the checksum calculation is case-sensitive. Later on, the human-readable part is converted to lower case before inclusion in the final output. If the original HumanReadablePart contained one or more upper case characters, the checksum will be inconsistent with the human readable part of the final output.
--| Encode a human-readable string and data payload into a Bech32 string. encode::HumanReadablePart->ByteString->EitherEncodingErrorByteString
encode hrp@(HumanReadablePart hrpBytes) payload =dolet payload5 = toBase32 (BS.unpack payload)
let payload' = payload5 ++ bech32CreateChecksum hrp payload5
let rest =map (word5ToChar Arr.!) payload'
let output =B8.map toLower hrpBytes <>B8.pack "1"<>B8.pack rest
guardE (BS.length output <= encodedStringMaxLength) EncodedStringTooLongreturn output
Why this is definitely a bug
The Bech32 specification states:
"The lowercase form is used when determining a character's value for checksum purposes."
Also, comparing with another official (JavaScript) implementation bitcoinjs/bech32
Added an extra regression test to highlight the bug described above: Codec/Binary/Bech32Spec
Also adjusted our arbitrary generator to produce uppercased and lowercased human-readable-part and have roundtrip properties check for both (was only producing lowercased HRP before).
Behavior is now aligned with another (more maintained) reference implementation a.k.a bitcoinjs/bech32
The text was updated successfully, but these errors were encountered:
jonathanknowles
changed the title
Bech32 encode function can be coerced into producing a string that can't be decoded with decode.
Bech32 encoder can be coerced into producing a string that can't be decoded
May 24, 2019
Context
When
encode
is applied to aHumanReadablePart
containing one or more upper-case characters, it results in an invalid Bech32 string that cannot be decoded with thedecode
function.Steps to Reproduce
Expected behaviour
Actual behaviour
Cause
This appears to be caused by the
encode
function. Internally, it calculates a checksum based on the suppliedHumanReadablePart
, which can be upper or lower case (or mixed case). Unfortunately, the checksum calculation is case-sensitive. Later on, the human-readable part is converted to lower case before inclusion in the final output. If the originalHumanReadablePart
contained one or more upper case characters, the checksum will be inconsistent with the human readable part of the final output.Why this is definitely a bug
The Bech32 specification states:
Also, comparing with another official (JavaScript) implementation bitcoinjs/bech32
We have the following behavior:
which is quite aligned with what we now expect and suggest the existence of a bug in the haskell implementation.
Addendum
This bug appears to also affect the Haskell reference implementation for Bech32.
QA
Added an extra regression test to highlight the bug described above: Codec/Binary/Bech32Spec
Also adjusted our arbitrary generator to produce uppercased and lowercased human-readable-part and have roundtrip properties check for both (was only producing lowercased HRP before).
Behavior is now aligned with another (more maintained) reference implementation a.k.a bitcoinjs/bech32
The text was updated successfully, but these errors were encountered: