Base64.sol 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol)
  3. pragma solidity ^0.8.0;
  4. /**
  5. * @dev Provides a set of functions to operate with Base64 strings.
  6. *
  7. * _Available since v4.5._
  8. */
  9. library Base64 {
  10. /**
  11. * @dev Base64 Encoding/Decoding Table
  12. */
  13. string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  14. /**
  15. * @dev Converts a `bytes` to its Bytes64 `string` representation.
  16. */
  17. function encode(bytes memory data) internal pure returns (string memory) {
  18. /**
  19. * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
  20. * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
  21. */
  22. if (data.length == 0) return "";
  23. // Loads the table into memory
  24. string memory table = _TABLE;
  25. // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
  26. // and split into 4 numbers of 6 bits.
  27. // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
  28. // - `data.length + 2` -> Round up
  29. // - `/ 3` -> Number of 3-bytes chunks
  30. // - `4 *` -> 4 characters for each chunk
  31. string memory result = new string(4 * ((data.length + 2) / 3));
  32. /// @solidity memory-safe-assembly
  33. assembly {
  34. // Prepare the lookup table (skip the first "length" byte)
  35. let tablePtr := add(table, 1)
  36. // Prepare result pointer, jump over length
  37. let resultPtr := add(result, 32)
  38. // Run over the input, 3 bytes at a time
  39. for {
  40. let dataPtr := data
  41. let endPtr := add(data, mload(data))
  42. } lt(dataPtr, endPtr) {
  43. } {
  44. // Advance 3 bytes
  45. dataPtr := add(dataPtr, 3)
  46. let input := mload(dataPtr)
  47. // To write each character, shift the 3 bytes (18 bits) chunk
  48. // 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
  49. // and apply logical AND with 0x3F which is the number of
  50. // the previous character in the ASCII table prior to the Base64 Table
  51. // The result is then added to the table to get the character to write,
  52. // and finally write it in the result pointer but with a left shift
  53. // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits
  54. mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
  55. resultPtr := add(resultPtr, 1) // Advance
  56. mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
  57. resultPtr := add(resultPtr, 1) // Advance
  58. mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
  59. resultPtr := add(resultPtr, 1) // Advance
  60. mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
  61. resultPtr := add(resultPtr, 1) // Advance
  62. }
  63. // When data `bytes` is not exactly 3 bytes long
  64. // it is padded with `=` characters at the end
  65. switch mod(mload(data), 3)
  66. case 1 {
  67. mstore8(sub(resultPtr, 1), 0x3d)
  68. mstore8(sub(resultPtr, 2), 0x3d)
  69. }
  70. case 2 {
  71. mstore8(sub(resultPtr, 1), 0x3d)
  72. }
  73. }
  74. return result;
  75. }
  76. }