base53-encoder
Version:
A unique Base53 encoding scheme with 30-bit block and 5-bit segment encoding
219 lines (205 loc) • 6.57 kB
JavaScript
function _arrayLikeToArray(r, a) {
(null == a || a > r.length) && (a = r.length);
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
return n;
}
function _createForOfIteratorHelper(r, e) {
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (!t) {
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) {
t && (r = t);
var n = 0,
F = function () {};
return {
s: F,
n: function () {
return n >= r.length ? {
done: true
} : {
done: false,
value: r[n++]
};
},
e: function (r) {
throw r;
},
f: F
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var o,
a = true,
u = false;
return {
s: function () {
t = t.call(r);
},
n: function () {
var r = t.next();
return a = r.done, r;
},
e: function (r) {
u = true, o = r;
},
f: function () {
try {
a || null == t.return || t.return();
} finally {
if (u) throw o;
}
}
};
}
function _unsupportedIterableToArray(r, a) {
if (r) {
if ("string" == typeof r) return _arrayLikeToArray(r, a);
var t = {}.toString.call(r).slice(8, -1);
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : undefined;
}
}
/**
* Base53 Encoding/Decoding Module
*
* A custom base encoding scheme that uses a 32-character encoding table
* with 5-bit segments, creating a 30-bit block encoding strategy.
*
* @module Base53
*/
/**
* Encoding table for Base53 encoding
* @type {string[]}
* @private
*/
var encodeTable = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'a', 'b', 'c', 'd', 'e', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'];
/**
* Binary mapping for each character in the encoding table
* @type {string[]}
* @private
*/
var binaryMapping = ['00000', '00001', '00010', '00011', '00100', '00101', '00110', '00111', '01000', '01001', '01010', '01011', '01100', '01101', '01110', '01111', '10000', '10001', '10010', '10011', '10100', '10101', '10110', '10111', '11000', '11001', '11010', '11011', '11100', '11101', '11110', '11111'];
/**
* Converts a string to its binary representation
*
* @param {string} str - Input string to convert
* @returns {string} Binary string representation
* @private
*/
function toBinaryString(str) {
return str.split('').map(function (c) {
return c.charCodeAt(0).toString(2).padStart(8, '0');
}).join('');
}
/**
* Converts a binary string back to its text representation
*
* @param {string} binStr - Binary string to convert
* @returns {string} Decoded text string
* @private
*/
function fromBinaryString(binStr) {
var bytes = binStr.match(/.{8}/g) || [];
return bytes.map(function (_byte) {
return String.fromCharCode(parseInt(_byte, 2));
}).join('');
}
/**
* Encodes a string using Base53 encoding
*
* @param {string} input - Input string to encode
* @returns {string} Base53 encoded string
*/
function base53_encode(input) {
if (input.length === 0) return '';
var binaryString = toBinaryString(input);
var blockSize = 30; // Block size in bits (6 segments of 5 bits each)
// Pad binary string to a multiple of blockSize
var paddingLength = (blockSize - binaryString.length % blockSize) % blockSize;
var paddedBinaryString = binaryString + '0'.repeat(paddingLength);
var encodedString = '';
for (var i = 0; i < paddedBinaryString.length; i += blockSize) {
var block = paddedBinaryString.substr(i, blockSize);
for (var j = 0; j < blockSize; j += 5) {
var segment = block.substr(j, 5);
var index = parseInt(segment, 2);
encodedString += encodeTable[index];
}
}
return encodedString;
}
/**
* Decodes a Base53 encoded string
*
* @param {string} encoded - Base53 encoded string to decode
* @returns {string} Decoded original string
*/
function base53_decode(encoded) {
if (encoded.length === 0) return '';
var binaryString = '';
var _iterator = _createForOfIteratorHelper(encoded),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var _char = _step.value;
var index = encodeTable.indexOf(_char);
if (index === -1) throw new Error('Invalid character in encoded string');
binaryString += binaryMapping[index];
}
// Remove trailing zeros
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
while (binaryString.length > 0 && binaryString.slice(-8) === '00000000') {
binaryString = binaryString.slice(0, -8);
}
var byteString = binaryString.match(/.{8}/g) || [];
return fromBinaryString(byteString.join(''));
}
/**
* Generates a random string of specified length
*
* @param {number} length - Length of the random string
* @returns {string} Generated random string
*/
function generateRandomString(length) {
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var result = '';
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
/**
* Builds a 150-bit key using Base53 encoding
*
* @param {number} [numSegments=5] - Number of segments to generate
* @param {number} [segmentLength=32] - Length of each random string segment
* @returns {Object} Object containing raw, encoded, and decoded key
*/
function buildBase53Key() {
var numSegments = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 5;
var segmentLength = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 32;
var rawKey = '';
for (var i = 0; i < numSegments; i++) {
var randomString = generateRandomString(segmentLength);
var encodedSegment = base53_encode(randomString);
rawKey += encodedSegment;
}
var encodedKey = base53_encode(rawKey);
var decodedKey = base53_decode(encodedKey);
return {
rawKey: rawKey,
encodedKey: encodedKey,
decodedKey: decodedKey
};
}
// Export the module's key functions
var Base53 = {
encode: base53_encode,
decode: base53_decode,
buildKey: buildBase53Key
};
export { Base53, Base53 as default };