Add Base64Url encoding (#4822)
Co-authored-by: Ernesto García <ernestognw@gmail.com>
This commit is contained in:
@ -9,29 +9,48 @@ pragma solidity ^0.8.20;
|
||||
library Base64 {
|
||||
/**
|
||||
* @dev Base64 Encoding/Decoding Table
|
||||
* See sections 4 and 5 of https://datatracker.ietf.org/doc/html/rfc4648
|
||||
*/
|
||||
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
string internal constant _TABLE_URL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
|
||||
/**
|
||||
* @dev Converts a `bytes` to its Bytes64 `string` representation.
|
||||
*/
|
||||
function encode(bytes memory data) internal pure returns (string memory) {
|
||||
return _encode(data, _TABLE, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Converts a `bytes` to its Bytes64Url `string` representation.
|
||||
*/
|
||||
function encodeURL(bytes memory data) internal pure returns (string memory) {
|
||||
return _encode(data, _TABLE_URL, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal table-agnostic conversion
|
||||
*/
|
||||
function _encode(bytes memory data, string memory table, bool withPadding) private 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
|
||||
// If padding is enabled, the final length should be `bytes` data length divided by 3 rounded up and then
|
||||
// multiplied by 4 so that it leaves room for padding the last chunk
|
||||
// - `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));
|
||||
// If padding is disabled, the final length should be `bytes` data length multiplied by 4/3 rounded up as
|
||||
// opposed to when padding is required to fill the last chunk.
|
||||
// - `4 *` -> 4 characters for each chunk
|
||||
// - `data.length + 2` -> Round up
|
||||
// - `/ 3` -> Number of 3-bytes chunks
|
||||
uint256 resultLength = withPadding ? 4 * ((data.length + 2) / 3) : (4 * data.length + 2) / 3;
|
||||
|
||||
string memory result = new string(resultLength);
|
||||
|
||||
/// @solidity memory-safe-assembly
|
||||
assembly {
|
||||
@ -73,15 +92,17 @@ library Base64 {
|
||||
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)
|
||||
if withPadding {
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user