damus.io

damus.io website
git clone git://jb55.com/damus.io
Log | Files | Refs | README

bech32.js (5162B)


      1 var ALPHABET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
      2 var ALPHABET_MAP = {};
      3 for (var z = 0; z < ALPHABET.length; z++) {
      4     var x = ALPHABET.charAt(z);
      5     ALPHABET_MAP[x] = z;
      6 }
      7 function polymodStep(pre) {
      8     var b = pre >> 25;
      9     return (((pre & 0x1ffffff) << 5) ^
     10         (-((b >> 0) & 1) & 0x3b6a57b2) ^
     11         (-((b >> 1) & 1) & 0x26508e6d) ^
     12         (-((b >> 2) & 1) & 0x1ea119fa) ^
     13         (-((b >> 3) & 1) & 0x3d4233dd) ^
     14         (-((b >> 4) & 1) & 0x2a1462b3));
     15 }
     16 function prefixChk(prefix) {
     17     var chk = 1;
     18     for (var i = 0; i < prefix.length; ++i) {
     19         var c = prefix.charCodeAt(i);
     20         if (c < 33 || c > 126)
     21             return 'Invalid prefix (' + prefix + ')';
     22         chk = polymodStep(chk) ^ (c >> 5);
     23     }
     24     chk = polymodStep(chk);
     25     for (var i = 0; i < prefix.length; ++i) {
     26         var v = prefix.charCodeAt(i);
     27         chk = polymodStep(chk) ^ (v & 0x1f);
     28     }
     29     return chk;
     30 }
     31 function convertbits(data, inBits, outBits, pad) {
     32     var value = 0;
     33     var bits = 0;
     34     var maxV = (1 << outBits) - 1;
     35     var result = [];
     36     for (var i = 0; i < data.length; ++i) {
     37         value = (value << inBits) | data[i];
     38         bits += inBits;
     39         while (bits >= outBits) {
     40             bits -= outBits;
     41             result.push((value >> bits) & maxV);
     42         }
     43     }
     44     if (pad) {
     45         if (bits > 0) {
     46             result.push((value << (outBits - bits)) & maxV);
     47         }
     48     }
     49     else {
     50         if (bits >= inBits)
     51             return 'Excess padding';
     52         if ((value << (outBits - bits)) & maxV)
     53             return 'Non-zero padding';
     54     }
     55     return result;
     56 }
     57 function toWords(bytes) {
     58     return convertbits(bytes, 8, 5, true);
     59 }
     60 function fromWordsUnsafe(words) {
     61     var res = convertbits(words, 5, 8, false);
     62     if (Array.isArray(res))
     63         return res;
     64 }
     65 function fromWords(words) {
     66     var res = convertbits(words, 5, 8, false);
     67     if (Array.isArray(res))
     68         return res;
     69     throw new Error(res);
     70 }
     71 function getLibraryFromEncoding(encoding) {
     72     var ENCODING_CONST;
     73     if (encoding === 'bech32') {
     74         ENCODING_CONST = 1;
     75     }
     76     else {
     77         ENCODING_CONST = 0x2bc830a3;
     78     }
     79     function encode(prefix, words, LIMIT) {
     80         LIMIT = LIMIT || 90;
     81         if (prefix.length + 7 + words.length > LIMIT)
     82             throw new TypeError('Exceeds length limit');
     83         prefix = prefix.toLowerCase();
     84         // determine chk mod
     85         var chk = prefixChk(prefix);
     86         if (typeof chk === 'string')
     87             throw new Error(chk);
     88         var result = prefix + '1';
     89         for (var i = 0; i < words.length; ++i) {
     90             var x = words[i];
     91             if (x >> 5 !== 0)
     92                 throw new Error('Non 5-bit word');
     93             chk = polymodStep(chk) ^ x;
     94             result += ALPHABET.charAt(x);
     95         }
     96         for (var i = 0; i < 6; ++i) {
     97             chk = polymodStep(chk);
     98         }
     99         chk ^= ENCODING_CONST;
    100         for (var i = 0; i < 6; ++i) {
    101             var v = (chk >> ((5 - i) * 5)) & 0x1f;
    102             result += ALPHABET.charAt(v);
    103         }
    104         return result;
    105     }
    106     function __decode(str, LIMIT) {
    107         LIMIT = LIMIT || 90;
    108         if (str.length < 8)
    109             return str + ' too short';
    110         if (str.length > LIMIT)
    111             return 'Exceeds length limit';
    112         // don't allow mixed case
    113         var lowered = str.toLowerCase();
    114         var uppered = str.toUpperCase();
    115         if (str !== lowered && str !== uppered)
    116             return 'Mixed-case string ' + str;
    117         str = lowered;
    118         var split = str.lastIndexOf('1');
    119         if (split === -1)
    120             return 'No separator character for ' + str;
    121         if (split === 0)
    122             return 'Missing prefix for ' + str;
    123         var prefix = str.slice(0, split);
    124         var wordChars = str.slice(split + 1);
    125         if (wordChars.length < 6)
    126             return 'Data too short';
    127         var chk = prefixChk(prefix);
    128         if (typeof chk === 'string')
    129             return chk;
    130         var words = [];
    131         for (var i = 0; i < wordChars.length; ++i) {
    132             var c = wordChars.charAt(i);
    133             var v = ALPHABET_MAP[c];
    134             if (v === undefined)
    135                 return 'Unknown character ' + c;
    136             chk = polymodStep(chk) ^ v;
    137             // not in the checksum?
    138             if (i + 6 >= wordChars.length)
    139                 continue;
    140             words.push(v);
    141         }
    142         if (chk !== ENCODING_CONST)
    143             return 'Invalid checksum for ' + str;
    144         return { prefix: prefix, words: words };
    145     }
    146     function decodeUnsafe(str, LIMIT) {
    147         var res = __decode(str, LIMIT);
    148         if (typeof res === 'object')
    149             return res;
    150     }
    151     function decode(str, LIMIT) {
    152         var res = __decode(str, LIMIT);
    153         if (typeof res === 'object')
    154             return res;
    155         throw new Error(res);
    156     }
    157     return {
    158         decodeUnsafe: decodeUnsafe,
    159         decode: decode,
    160         encode: encode,
    161         toWords: toWords,
    162         fromWordsUnsafe: fromWordsUnsafe,
    163         fromWords: fromWords
    164     };
    165 }
    166 
    167 const bech32 = getLibraryFromEncoding('bech32');
    168 const bech32m = getLibraryFromEncoding('bech32m');
    169