Created
April 8, 2024 04:06
-
-
Save mingderwang/4a1023b7454d33bb4b75e35c95234867 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* solhint-disable */ | |
// SPDX-License-Identifier: MIT | |
// from OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol) | |
pragma solidity ^0.8.19; | |
/** | |
* @dev Provides a set of functions to operate with Base64 strings. | |
* | |
* _Available since v4.5._ | |
*/ | |
library Base64URL { | |
/** | |
* @dev Base64 Encoding/Decoding Table | |
*/ | |
string internal constant _TABLE = | |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; | |
/** | |
* @dev Converts a `bytes` to its Bytes64 `string` representation. | |
*/ | |
function encode32(bytes memory data) internal pure returns (string memory) { | |
/** | |
* Inspired by Brecht Devos (Brechtpd) implementation - MIT licence | |
* https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol | |
*/ | |
if (data.length == 0) return ""; | |
// Loads the table into memory | |
string memory table = _TABLE; | |
// Encoding takes 3 bytes chunks of binary data from `bytes` data parameter | |
// and split into 4 numbers of 6 bits. | |
// The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up | |
// - `data.length + 2` -> Round up | |
// - `/ 3` -> Number of 3-bytes chunks | |
// - `4 *` -> 4 characters for each chunk | |
//string memory result = new string(4 * ((data.length + 2) / 3)); | |
string memory result = new string(4 * ((data.length + 2) / 3) - 1); | |
/// @solidity memory-safe-assembly | |
// @solhint-disable-next-line no-inline-assembly | |
assembly { | |
// Prepare the lookup table (skip the first "length" byte) | |
let tablePtr := add(table, 1) | |
// Prepare result pointer, jump over length | |
let resultPtr := add(result, 32) | |
// Run over the input, 3 bytes at a time | |
for { | |
let dataPtr := data | |
let endPtr := add(data, mload(data)) | |
} lt(dataPtr, endPtr) { } { | |
// Advance 3 bytes | |
dataPtr := add(dataPtr, 3) | |
let input := mload(dataPtr) | |
// To write each character, shift the 3 bytes (18 bits) chunk | |
// 4 times in blocks of 6 bits for each character (18, 12, 6, 0) | |
// and apply logical AND with 0x3F which is the number of | |
// the previous character in the ASCII table prior to the Base64 Table | |
// The result is then added to the table to get the character to write, | |
// and finally write it in the result pointer but with a left shift | |
// of 256 (1 byte) - 8 (1 ASCII char) = 248 bits | |
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) | |
resultPtr := add(resultPtr, 1) // Advance | |
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) | |
resultPtr := add(resultPtr, 1) // Advance | |
mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) | |
resultPtr := add(resultPtr, 1) // Advance | |
mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) | |
resultPtr := add(resultPtr, 1) // Advance | |
} | |
/* | |
// When data `bytes` is not exactly 3 bytes long | |
// it is padded with `=` characters at the end | |
switch mod(mload(data), 3) | |
case 1 { | |
mstore8(sub(resultPtr, 1), 0x3d) | |
mstore8(sub(resultPtr, 2), 0x3d) | |
} | |
case 2 { | |
mstore8(sub(resultPtr, 1), 0x3d) | |
} | |
*/ | |
} | |
return result; | |
} | |
} | |
/* solhint-enable */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./Base64URL.sol";
contract MyContract {
function encode(bytes memory _data) public pure returns (string memory) {
return Base64URL.encode32(_data);
}
}