github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/www/resources/bech32.js (about)

     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  
    21  var CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
    22  var GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
    23  
    24  const encodings = {
    25    BECH32: "bech32",
    26    BECH32M: "bech32m",
    27  };
    28  function getEncodingConst (enc) {
    29    if (enc == encodings.BECH32) {
    30      return 1;
    31    } else if (enc == encodings.BECH32M) {
    32      return 0x2bc830a3;
    33    } else {
    34      return null;
    35    }
    36  }
    37  
    38  function polymod (values) {
    39    var chk = 1;
    40    for (var p = 0; p < values.length; ++p) {
    41      var top = chk >> 25;
    42      chk = (chk & 0x1ffffff) << 5 ^ values[p];
    43      for (var i = 0; i < 5; ++i) {
    44        if ((top >> i) & 1) {
    45          chk ^= GENERATOR[i];
    46        }
    47      }
    48    }
    49    return chk;
    50  }
    51  
    52  function hrpExpand (hrp) {
    53    var ret = [];
    54    var p;
    55    for (p = 0; p < hrp.length; ++p) {
    56      ret.push(hrp.charCodeAt(p) >> 5);
    57    }
    58    ret.push(0);
    59    for (p = 0; p < hrp.length; ++p) {
    60      ret.push(hrp.charCodeAt(p) & 31);
    61    }
    62    return ret;
    63  }
    64  
    65  function verifyChecksum (hrp, data, enc) {
    66    return polymod(hrpExpand(hrp).concat(data)) === getEncodingConst(enc);
    67  }
    68  
    69  function createChecksum (hrp, data, enc) {
    70    var values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);
    71    var mod = polymod(values) ^ getEncodingConst(enc);
    72    var ret = [];
    73    for (var p = 0; p < 6; ++p) {
    74      ret.push((mod >> 5 * (5 - p)) & 31);
    75    }
    76    return ret;
    77  }
    78  
    79  function bech32_encode (hrp, data, enc) {
    80    var combined = data.concat(createChecksum(hrp, data, enc));
    81    var ret = hrp + '1';
    82    for (var p = 0; p < combined.length; ++p) {
    83      ret += CHARSET.charAt(combined[p]);
    84    }
    85    return ret;
    86  }
    87  
    88  function bech32_decode (bechString, enc) {
    89    var p;
    90    var has_lower = false;
    91    var has_upper = false;
    92    for (p = 0; p < bechString.length; ++p) {
    93      if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) {
    94        return null;
    95      }
    96      if (bechString.charCodeAt(p) >= 97 && bechString.charCodeAt(p) <= 122) {
    97          has_lower = true;
    98      }
    99      if (bechString.charCodeAt(p) >= 65 && bechString.charCodeAt(p) <= 90) {
   100          has_upper = true;
   101      }
   102    }
   103    if (has_lower && has_upper) {
   104      return null;
   105    }
   106    bechString = bechString.toLowerCase();
   107    var pos = bechString.lastIndexOf('1');
   108    if (pos < 1 || pos + 7 > bechString.length || bechString.length > 90) {
   109      return null;
   110    }
   111    var hrp = bechString.substring(0, pos);
   112    var data = [];
   113    for (p = pos + 1; p < bechString.length; ++p) {
   114      var d = CHARSET.indexOf(bechString.charAt(p));
   115      if (d === -1) {
   116        return null;
   117      }
   118      data.push(d);
   119    }
   120    if (!verifyChecksum(hrp, data, enc)) {
   121      return null;
   122    }
   123    return {hrp: hrp, data: data.slice(0, data.length - 6)};
   124  }
   125  
   126  function convertbits (data, frombits, tobits, pad) {
   127    var acc = 0;
   128    var bits = 0;
   129    var ret = [];
   130    var maxv = (1 << tobits) - 1;
   131    for (var p = 0; p < data.length; ++p) {
   132      var value = data[p];
   133      if (value < 0 || (value >> frombits) !== 0) {
   134        return null;
   135      }
   136      acc = (acc << frombits) | value;
   137      bits += frombits;
   138      while (bits >= tobits) {
   139        bits -= tobits;
   140        ret.push((acc >> bits) & maxv);
   141      }
   142    }
   143    if (pad) {
   144      if (bits > 0) {
   145        ret.push((acc << (tobits - bits)) & maxv);
   146      }
   147    } else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) {
   148      return null;
   149    }
   150    return ret;
   151  }
   152  
   153  function sw_decode (hrp, addr) {
   154    var bech32m = false;
   155    var dec = bech32_decode(addr, encodings.BECH32);
   156    if (dec === null) {
   157      dec = bech32_decode(addr, encodings.BECH32M);
   158      bech32m = true;
   159    }
   160    if (dec === null || dec.hrp !== hrp || dec.data.length < 1 || dec.data[0] > 16) {
   161      return null;
   162    }
   163    var res = convertbits(dec.data.slice(1), 5, 8, false);
   164    if (res === null || res.length < 2 || res.length > 40) {
   165      return null;
   166    }
   167    if (dec.data[0] === 0 && res.length !== 20 && res.length !== 32) {
   168      return null;
   169    }
   170    if (dec.data[0] === 0 && bech32m) {
   171      return null;
   172    }
   173    if (dec.data[0] !== 0 && !bech32m) {
   174      return null;
   175    }
   176    return {version: dec.data[0], program: res};
   177  }
   178  
   179  function sw_encode (hrp, version, program) {
   180    var enc = encodings.BECH32;
   181    if (version > 0) {
   182      enc = encodings.BECH32M;
   183    }
   184    var ret = bech32_encode(hrp, [version].concat(convertbits(program, 8, 5, true)), enc);
   185    if (sw_decode(hrp, ret, enc) === null) {
   186      return null;
   187    }
   188    return ret;
   189  }