Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/utils/Base58.sol
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,17 @@ library Base58 {

for { let j := 0 } 1 {} {
let c := sub(byte(0, mload(add(s, j))), 49)
// Check if the input character is valid before `mload(c)`.
// Otherwise an out-of-bounds `c` expands memory and reverts
// with out-of-gas instead of `Base58DecodingError`.
if iszero(and(shl(c, 1), 0x3fff7ff03ffbeff01ff)) {
mstore(0x00, 0xe8fad793) // `Base58DecodingError()`.
revert(0x1c, 0x04)
}
let p := mul(result, 58)
let acc := add(byte(0, mload(c)), p)
// Check if the input character is valid.
if iszero(and(0x3fff7ff03ffbeff01ff, shl(c, lt(lt(acc, p), lt(result, t))))) {
// Check for multiplication or addition overflow.
if iszero(lt(lt(acc, p), lt(result, t))) {
mstore(0x00, 0xe8fad793) // `Base58DecodingError()`.
revert(0x1c, 0x04)
}
Expand Down
15 changes: 15 additions & 0 deletions test/Base58.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,21 @@ contract Base58Test is SoladyTest {
this.decodeWord("JEKNVnkbo3jma5nREBBJCDoXFVeKkD56V3xKrvRmWxFH@");
}

function testDecodeWordLowCharacterReverts() public {
// Characters below '1' (0x31) underflow the lookup index. The
// sanitizer must run before `mload(c)`, otherwise the out-of-bounds
// load expands memory and reverts with out-of-gas instead of a clean
// `Base58DecodingError`. See https://github.com/Vectorized/solady/issues/1543.
vm.expectRevert(Base58.Base58DecodingError.selector);
this.decodeWord("0");
vm.expectRevert(Base58.Base58DecodingError.selector);
this.decodeWord("\x00");
// Also cover an underflowing byte after a valid character, where
// `result` is already nonzero (loop position > 0).
vm.expectRevert(Base58.Base58DecodingError.selector);
this.decodeWord("z0");
}

function decodeWord(string memory encoded) public pure returns (bytes32) {
return Base58.decodeWord(encoded);
}
Expand Down