/ref/javascript/bech32.js

https://github.com/sipa/bech32 · JavaScript · 131 lines · 102 code · 10 blank · 19 comment · 28 complexity · ac69e12737ac30cf5046bff9b0b2b873 MD5 · raw file

  1. // Copyright (c) 2017, 2021 Pieter Wuille
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE.
  20. var CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
  21. var GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
  22. const encodings = {
  23. BECH32: "bech32",
  24. BECH32M: "bech32m",
  25. };
  26. module.exports = {
  27. decode: decode,
  28. encode: encode,
  29. encodings: encodings,
  30. };
  31. function getEncodingConst (enc) {
  32. if (enc == encodings.BECH32) {
  33. return 1;
  34. } else if (enc == encodings.BECH32M) {
  35. return 0x2bc830a3;
  36. } else {
  37. return null;
  38. }
  39. }
  40. function polymod (values) {
  41. var chk = 1;
  42. for (var p = 0; p < values.length; ++p) {
  43. var top = chk >> 25;
  44. chk = (chk & 0x1ffffff) << 5 ^ values[p];
  45. for (var i = 0; i < 5; ++i) {
  46. if ((top >> i) & 1) {
  47. chk ^= GENERATOR[i];
  48. }
  49. }
  50. }
  51. return chk;
  52. }
  53. function hrpExpand (hrp) {
  54. var ret = [];
  55. var p;
  56. for (p = 0; p < hrp.length; ++p) {
  57. ret.push(hrp.charCodeAt(p) >> 5);
  58. }
  59. ret.push(0);
  60. for (p = 0; p < hrp.length; ++p) {
  61. ret.push(hrp.charCodeAt(p) & 31);
  62. }
  63. return ret;
  64. }
  65. function verifyChecksum (hrp, data, enc) {
  66. return polymod(hrpExpand(hrp).concat(data)) === getEncodingConst(enc);
  67. }
  68. function createChecksum (hrp, data, enc) {
  69. var values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);
  70. var mod = polymod(values) ^ getEncodingConst(enc);
  71. var ret = [];
  72. for (var p = 0; p < 6; ++p) {
  73. ret.push((mod >> 5 * (5 - p)) & 31);
  74. }
  75. return ret;
  76. }
  77. function encode (hrp, data, enc) {
  78. var combined = data.concat(createChecksum(hrp, data, enc));
  79. var ret = hrp + '1';
  80. for (var p = 0; p < combined.length; ++p) {
  81. ret += CHARSET.charAt(combined[p]);
  82. }
  83. return ret;
  84. }
  85. function decode (bechString, enc) {
  86. var p;
  87. var has_lower = false;
  88. var has_upper = false;
  89. for (p = 0; p < bechString.length; ++p) {
  90. if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) {
  91. return null;
  92. }
  93. if (bechString.charCodeAt(p) >= 97 && bechString.charCodeAt(p) <= 122) {
  94. has_lower = true;
  95. }
  96. if (bechString.charCodeAt(p) >= 65 && bechString.charCodeAt(p) <= 90) {
  97. has_upper = true;
  98. }
  99. }
  100. if (has_lower && has_upper) {
  101. return null;
  102. }
  103. bechString = bechString.toLowerCase();
  104. var pos = bechString.lastIndexOf('1');
  105. if (pos < 1 || pos + 7 > bechString.length || bechString.length > 90) {
  106. return null;
  107. }
  108. var hrp = bechString.substring(0, pos);
  109. var data = [];
  110. for (p = pos + 1; p < bechString.length; ++p) {
  111. var d = CHARSET.indexOf(bechString.charAt(p));
  112. if (d === -1) {
  113. return null;
  114. }
  115. data.push(d);
  116. }
  117. if (!verifyChecksum(hrp, data, enc)) {
  118. return null;
  119. }
  120. return {hrp: hrp, data: data.slice(0, data.length - 6)};
  121. }