UNPKG

@unstoppabledomains/resolution

Version:
232 lines (231 loc) 7.54 kB
"use strict"; /** * All functionality below came from here https://github.com/Zilliqa/Zilliqa-JavaScript-Library/tree/dev/packages/zilliqa-js-crypto/src */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.fromBech32Address = exports.toBech32Address = exports.toChecksumAddress = void 0; var bn_js_1 = __importDefault(require("bn.js")); var sha256_1 = __importDefault(require("crypto-js/sha256")); var enc_hex_1 = __importDefault(require("crypto-js/enc-hex")); var CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'; var GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]; // HRP is the human-readable part of zilliqa bech32 addresses var HRP = 'zil'; var tHRP = 'tzil'; function isByteString(str, len) { return !!str.replace('0x', '').match("^[0-9a-fA-F]{".concat(len, "}$")); } function isAddress(address) { return isByteString(address, 40); } /** * convertBits * * groups buffers of a certain width to buffers of the desired width. * * For example, converts byte buffers to buffers of maximum 5 bit numbers, * padding those numbers as necessary. Necessary for encoding Ethereum-style * addresses as bech32 ones. * @param {Buffer} data * @param {number} fromWidth * @param {number} toWidth * @param {boolean} pad * @returns {Buffer|null} */ function convertBits(data, fromWidth, toWidth, pad) { if (pad === void 0) { pad = true; } var acc = 0; var bits = 0; var ret = []; var maxv = (1 << toWidth) - 1; // tslint:disable-next-line for (var p = 0; p < data.length; ++p) { var value = data[p]; if (value < 0 || value >> fromWidth !== 0) { return null; } acc = (acc << fromWidth) | value; bits += fromWidth; while (bits >= toWidth) { bits -= toWidth; ret.push((acc >> bits) & maxv); } } if (pad) { if (bits > 0) { ret.push((acc << (toWidth - bits)) & maxv); } } else if (bits >= fromWidth || (acc << (toWidth - bits)) & maxv) { return null; } return Buffer.from(ret); } function hrpExpand(hrp) { var ret = []; var p; for (p = 0; p < hrp.length; ++p) { ret.push(hrp.charCodeAt(p) >> 5); } ret.push(0); for (p = 0; p < hrp.length; ++p) { ret.push(hrp.charCodeAt(p) & 31); } return Buffer.from(ret); } function polymod(values) { var chk = 1; // tslint:disable-next-line for (var p = 0; p < values.length; ++p) { var top_1 = chk >> 25; chk = ((chk & 0x1ffffff) << 5) ^ values[p]; for (var i = 0; i < 5; ++i) { if ((top_1 >> i) & 1) { chk ^= GENERATOR[i]; } } } return chk; } function createChecksum(hrp, data) { var values = Buffer.concat([ Buffer.from(hrpExpand(hrp)), data, Buffer.from([0, 0, 0, 0, 0, 0]), ]); // var values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]); var mod = polymod(values) ^ 1; var ret = []; for (var p = 0; p < 6; ++p) { ret.push((mod >> (5 * (5 - p))) & 31); } return Buffer.from(ret); } function verifyChecksum(hrp, data) { return polymod(Buffer.concat([hrpExpand(hrp), data])) === 1; } function encode(hrp, data) { var combined = Buffer.concat([data, createChecksum(hrp, data)]); var ret = hrp + '1'; // tslint:disable-next-line for (var p = 0; p < combined.length; ++p) { ret += CHARSET.charAt(combined[p]); } return ret; } function decode(bechString) { var p; var hasLower = false; var hasUpper = false; for (p = 0; p < bechString.length; ++p) { if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) { return null; } if (bechString.charCodeAt(p) >= 97 && bechString.charCodeAt(p) <= 122) { hasLower = true; } if (bechString.charCodeAt(p) >= 65 && bechString.charCodeAt(p) <= 90) { hasUpper = true; } } if (hasLower && hasUpper) { return null; } bechString = bechString.toLowerCase(); var pos = bechString.lastIndexOf('1'); if (pos < 1 || pos + 7 > bechString.length || bechString.length > 90) { return null; } var hrp = bechString.substring(0, pos); var data = []; for (p = pos + 1; p < bechString.length; ++p) { var d = CHARSET.indexOf(bechString.charAt(p)); if (d === -1) { return null; } data.push(d); } if (!verifyChecksum(hrp, Buffer.from(data))) { return null; } return { hrp: hrp, data: Buffer.from(data.slice(0, data.length - 6)) }; } /** * toChecksumAddress * * takes hex-encoded string and returns the corresponding address * @param {string} address * @returns {string} */ var toChecksumAddress = function (address) { if (!isAddress(address)) { throw new Error("".concat(address, " is not a valid base 16 address")); } address = address.toLowerCase().replace('0x', ''); var hash = enc_hex_1.default.stringify((0, sha256_1.default)(enc_hex_1.default.parse(address))); var v = new bn_js_1.default(hash, 'hex', 'be'); var ret = '0x'; for (var i = 0; i < address.length; i++) { if ('0123456789'.indexOf(address[i]) !== -1) { ret += address[i]; } else { ret += v.and(new bn_js_1.default(2).pow(new bn_js_1.default(255 - 6 * i))).gte(new bn_js_1.default(1)) ? address[i].toUpperCase() : address[i].toLowerCase(); } } return ret; }; exports.toChecksumAddress = toChecksumAddress; /** * toBech32Address * * Encodes a canonical 20-byte Ethereum-style address as a bech32 zilliqa * address. * * The expected format is zil1<address><checksum> where address and checksum * are the result of bech32 encoding a Buffer containing the address bytes. * @param {string} address 20 byte canonical address * @param {boolean} testnet * @returns {string} 38 char bech32 encoded zilliqa address */ function toBech32Address(address, testnet) { if (testnet === void 0) { testnet = false; } if (!isAddress(address)) { throw new Error('Invalid address format.'); } var addrBz = convertBits(Buffer.from(address.replace('0x', ''), 'hex'), 8, 5); if (addrBz === null) { throw new Error('Could not convert byte Buffer to 5-bit Buffer'); } return encode(testnet ? tHRP : HRP, addrBz); } exports.toBech32Address = toBech32Address; /** * fromBech32Address * @param {string} address - a valid Zilliqa bech32 address * @param {boolean} testnet * @returns {string} a canonical 20-byte Ethereum-style address */ function fromBech32Address(address, testnet) { if (testnet === void 0) { testnet = false; } var res = decode(address); if (res === null) { throw new Error('Invalid bech32 address'); } var hrp = res.hrp, data = res.data; var shouldBe = testnet ? tHRP : HRP; if (hrp !== shouldBe) { throw new Error("Expected hrp to be ".concat(shouldBe, " but got ").concat(hrp)); } var buf = convertBits(data, 5, 8, false); if (buf === null) { throw new Error('Could not convert buffer to bytes'); } return (0, exports.toChecksumAddress)(buf.toString('hex')); } exports.fromBech32Address = fromBech32Address;