hexUtils.dart 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. import 'dart:convert' show utf8;
  2. import 'dart:typed_data';
  3. import 'package:convert/convert.dart' show hex;
  4. import "package:pointycastle/digests/keccak.dart";
  5. bool isHexPrefixed(String str) {
  6. ArgumentError.checkNotNull(str);
  7. return str.startsWith('0x');
  8. }
  9. /// Is the string a hex string.
  10. bool isHexString(String value, {int length = 0}) {
  11. ArgumentError.checkNotNull(value);
  12. // if (!RegExp('^0x[0-9A-Fa-f]*\$').hasMatch(value)) return false;
  13. if (!RegExp(r'\b(?:0[xX])?[0-9a-fA-F]+\b').hasMatch(value)) return false;
  14. if (length > 0 && value.length != 2 + 2 * length) return false;
  15. return true;
  16. }
  17. String stripHexPrefix(String hexString) {
  18. ArgumentError.checkNotNull(hexString);
  19. if (hexString.startsWith("0x") || hexString.startsWith("0X")) {
  20. return hexString.substring(2);
  21. }
  22. return hexString;
  23. }
  24. String addHexPrefix(String hexString) {
  25. ArgumentError.checkNotNull(hexString);
  26. if (!hexString.startsWith("0x") && !hexString.startsWith("0X")) {
  27. return '0x$hexString';
  28. }
  29. return hexString;
  30. }
  31. /// Pads a [String] to have an even length
  32. String padToEven(String value) {
  33. ArgumentError.checkNotNull(value);
  34. var a = '$value';
  35. if (a.length % 2 == 1) a = '0${a}';
  36. return a;
  37. }
  38. /// Converts a [int] into a hex [String]
  39. String intToHex(i) {
  40. ArgumentError.checkNotNull(i);
  41. return '0x${i.toRadixString(16)}';
  42. }
  43. /// Converts an [int] or [BigInt] to a [Uint8List]
  44. Uint8List intToBuffer(i) {
  45. return Uint8List.fromList(i == null || i == 0 || i == BigInt.zero ? [] : hex.decode(padToEven(intToHex(i).substring(2))));
  46. }
  47. Uint8List stringToBuffer(String i) {
  48. return Uint8List.fromList(i.isEmpty ? [] : hex.decode(padToEven(stripHexPrefix(i))));
  49. }
  50. /// Get the binary size of a string
  51. int getBinarySize(String str) {
  52. ArgumentError.checkNotNull(str);
  53. return utf8.encode(str).length;
  54. }
  55. /// Returns TRUE if the first specified array contains all elements from the second one. FALSE otherwise.
  56. bool arrayContainsArray(List superset, List subset, {bool some = false}) {
  57. ArgumentError.checkNotNull(superset);
  58. ArgumentError.checkNotNull(subset);
  59. if (some) return Set.from(superset).intersection(Set.from(subset)).length > 0;
  60. return Set.from(superset).containsAll(subset);
  61. }
  62. /// Should be called to get utf8 from it's hex representation
  63. String toUtf8(String hexString) {
  64. ArgumentError.checkNotNull(hexString);
  65. List<int> bufferValue = hex.decode(padToEven(stripHexPrefix(hexString).replaceAll(RegExp('^0+|0+\$'), '')));
  66. return utf8.decode(bufferValue);
  67. }
  68. /// Should be called to get ascii from it's hex representation
  69. String toAscii(String hexString) {
  70. ArgumentError.checkNotNull(hexString);
  71. var start = hexString.startsWith(RegExp('^0x')) ? 2 : 0;
  72. return String.fromCharCodes(hex.decode(hexString.substring(start)));
  73. }
  74. /// Should be called to get hex representation (prefixed by 0x) of utf8 string
  75. String fromUtf8(String stringValue) {
  76. ArgumentError.checkNotNull(stringValue);
  77. var stringBuffer = utf8.encode(stringValue);
  78. return "0x${padToEven(hex.encode(stringBuffer)).replaceAll(RegExp('^0+|0+\$'), '')}";
  79. }
  80. /// Should be called to get hex representation (prefixed by 0x) of ascii string
  81. String fromAscii(String stringValue) {
  82. ArgumentError.checkNotNull(stringValue);
  83. var hexString = '';
  84. for (var i = 0; i < stringValue.length; i++) {
  85. var code = stringValue.codeUnitAt(i);
  86. var n = hex.encode([code]);
  87. hexString += n.length < 2 ? '0${n}' : n;
  88. }
  89. return '0x$hexString';
  90. }
  91. Uint8List hexToBytes(String hexStr) {
  92. final bytes = hex.decode(stripHexPrefix(hexStr));
  93. if (bytes is Uint8List) return bytes;
  94. return Uint8List.fromList(bytes);
  95. }
  96. String bytesToHex(List<int> bytes,
  97. {bool include0x = false,
  98. int? forcePadLength,
  99. bool padToEvenLength = false}) {
  100. var encoded = hex.encode(bytes);
  101. if (forcePadLength != null) {
  102. assert(forcePadLength >= encoded.length);
  103. final padding = forcePadLength - encoded.length;
  104. encoded = ('0' * padding) + encoded;
  105. }
  106. if (padToEvenLength && encoded.length % 2 != 0) encoded = '0$encoded';
  107. return (include0x ? '0x' : '') + encoded;
  108. }
  109. // ------------ by myself -----------
  110. String hex2ascii(String hexString) {
  111. try {
  112. if (isHexString(hexString)) {
  113. hexString = stripHexPrefix(hexString);
  114. List<String> splitted = [];
  115. for (int i = 0; i < hexString.length; i = i + 2) {
  116. splitted.add(hexString.substring(i, i + 2));
  117. }
  118. String ascii = List.generate(splitted.length,
  119. (i) => String.fromCharCode(int.parse(splitted[i], radix: 16))).join();
  120. return ascii;
  121. } else {
  122. return '';
  123. }
  124. } catch (error) {
  125. return '';
  126. }
  127. }
  128. String ascii2hex(String asciiString) {
  129. try {
  130. if (asciiString.isNotEmpty) {
  131. String hexStr = '';
  132. for (int i = 0; i < asciiString.length; ++i) {
  133. hexStr = hexStr + asciiString.codeUnitAt(i).toRadixString(16);
  134. }
  135. return hexStr;
  136. } else {
  137. return '';
  138. }
  139. } catch (error) {
  140. return '';
  141. }
  142. }
  143. String hex2dec(String hexString) {
  144. try {
  145. if (isHexString(hexString)) {
  146. BigInt? bgInt = BigInt.tryParse(stripHexPrefix(hexString), radix:16);
  147. if (bgInt != null) {
  148. return bgInt.toRadixString(10);
  149. }
  150. }
  151. // else
  152. return '';
  153. } catch (error) {
  154. return '';
  155. }
  156. }
  157. String dec2hex(String decString) {
  158. try {
  159. if (decString.isNotEmpty) {
  160. BigInt? bgInt = BigInt.tryParse(decString, radix:10);
  161. if (bgInt != null) {
  162. return addHexPrefix(bgInt.toRadixString(16));
  163. }
  164. }
  165. // else
  166. return '';
  167. } catch (error) {
  168. return '';
  169. }
  170. }
  171. /// ----- to Hash -----
  172. /// 注意:Hash256 和 Keccak256 其实不一样,
  173. /// 但由于最早接触 Ethereum 相关代码,其中 Hash 使用的是 Keccak256,
  174. /// 造成App其他地方的 Hash 也都沿用了 Keccak256。
  175. /// 历史原因,不做修改。[2023-12-15 James.Zhang]
  176. String toHash(String anyString) {
  177. return toKeccak256(anyString);
  178. }
  179. String toKeccak256(String anyString, [int bitLength = 256]) {
  180. var keccak = KeccakDigest(bitLength);
  181. keccak.update(
  182. Uint8List.fromList(anyString.codeUnits),
  183. 0,
  184. anyString.codeUnits.length,
  185. );
  186. var out = Uint8List(bitLength ~/ 8);
  187. keccak.doFinal(out, 0);
  188. return _uint8ListToHex(out);
  189. }
  190. /// Character `0`.
  191. const int _zero = 0x30;
  192. /// Character `a`.
  193. const int _a = 0x61;
  194. String _uint8ListToHex(List<int> bytes) {
  195. final buffer = Uint8List(bytes.length * 2);
  196. int bufferIndex = 0;
  197. for (var i = 0; i < bytes.length; i++) {
  198. var byte = bytes[i];
  199. // The bitwise arithmetic here is equivalent to `byte ~/ 16` and `byte % 16`
  200. // for valid byte values, but is easier for dart2js to optimize given that
  201. // it can't prove that [byte] will always be positive.
  202. buffer[bufferIndex++] = _codeUnitForDigit((byte & 0xF0) >> 4);
  203. buffer[bufferIndex++] = _codeUnitForDigit(byte & 0x0F);
  204. }
  205. return String.fromCharCodes(buffer);
  206. }
  207. /// Returns the ASCII/Unicode code unit corresponding to the hexadecimal digit
  208. /// [digit].
  209. int _codeUnitForDigit(int digit) =>
  210. digit < 10 ? digit + _zero : digit + _a - 10;