Skip to content

Instantly share code, notes, and snippets.

@Vectorized
Last active May 26, 2022 14:10
Show Gist options
  • Save Vectorized/e4b5736fdd24c32fb98b790f1bb36bfe to your computer and use it in GitHub Desktop.
Save Vectorized/e4b5736fdd24c32fb98b790f1bb36bfe to your computer and use it in GitHub Desktop.
Solidity Base64 Encode
// SPDX-License-Identifier: MIT
// Author: vectorized.eth
pragma solidity ^0.8.0;
library Base64 {
function encode(bytes memory data) internal pure returns (string memory result) {
// Inspired by (https://github.com/Brechtpd/base64/blob/main/base64.sol)
// by Brecht Devos - <brecht@loopring.org>. MIT licensed.
assembly {
let dataLength := mload(data)
if dataLength {
// Set `result` to point to the start of the free memory.
result := mload(0x40)
// Write the length of the string: `ceil(dataLength / 3.0 * 4.0)`.
mstore(result, shl(2, div(add(dataLength, 2), 3)))
// Store the table into the scratch space.
// Offsetted by -1 byte so that the `mload` will load the character.
// We will overwrite the free memory pointer at `0x40` later
// to allocate memory for the string.
mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef")
mstore(0x3f, "ghijklmnopqrstuvwxyz0123456789+/")
// Skip the first slot, which stores the length.
let ptr := add(result, 0x20)
let end := add(ptr, mload(result))
// Run over the input, 3 bytes at a time.
// prettier-ignore
for {} iszero(eq(ptr, end)) {} {
// Advance 3 bytes.
data := add(data, 3)
let input := mload(data)
// Write 4 characters.
mstore8(ptr, mload(and(shr(18, input), 0x3F)))
ptr := add(ptr, 1)
mstore8(ptr, mload(and(shr(12, input), 0x3F)))
ptr := add(ptr, 1)
mstore8(ptr, mload(and(shr( 6, input), 0x3F)))
ptr := add(ptr, 1)
mstore8(ptr, mload(and( input, 0x3F)))
ptr := add(ptr, 1)
}
// Padding with '='. We can simply write over the end.
let paddingOffset := byte(mod(dataLength, 3), "\x00\x02\x01")
mstore(sub(ptr, paddingOffset), "==")
// Updates the free memory pointer to allocate memory for the string.
// Add 32 to ensure a minimum of 1 32-byte word allocated.
// Then mask with ~31 to round down to a multiple of 32.
mstore(0x40, and(add(end, 32), not(0x1f)))
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment