@unstoppabledomains/resolution
Version:
Domain Resolution for blockchain domains
232 lines (231 loc) • 7.54 kB
JavaScript
"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;