digibyte-js
Version:
A pure and powerful JavaScript DigiByte library.
164 lines (153 loc) • 5.62 kB
JavaScript
function Precision() {
this._bits = "";
}
Precision.prototype = {
get length() {
return this._bits.length;
}
}
/**
* Returns a binary string representation of an integer in Bitcoin's precision encoding.
* @param {Number} value An integer value
* @returns
*/
Precision.precision = function (value) {
if (
(typeof value != "bigint") &&
((typeof value == "number") && (value !== Math.min(value)))
) throw new Error("Invalid Input Type"); //throw error if can't be included
value = BigInt(value);
if ((value < 0n) || (value > 18014398509481983n)) throw new Error("Invalid Input Type"); //throw error if can't be included
//see if can be done as 1 byte
if (value < 32n) {
// noinspection JSCheckFunctionSignatures
return value.toString(2).padStart(8, '0');
}
//compute exponent
let exponent = 0n;
while (value % 10n === 0n) {
exponent++;
value /= 10n;
}
if (value > 4398046511103n) { //max 0 exponent bits
value *= 10n ** exponent;
exponent = 0n;
} else if ((value > 33554431n) && (exponent > 7n)) {//max 3 exponent bits
value *= 10n ** (exponent - 7n);
exponent = 7n;
}
//return binary value
if (value > 4398046511103n) { //7 bytes
// noinspection JSCheckFunctionSignatures
return "11" + value.toString(2).padStart(54, '0');
} else if (value > 17179869183n) { //6 bytes
// noinspection JSCheckFunctionSignatures
return "101" + value.toString(2).padStart(42, '0') + exponent.toString(2).padStart(3, '0');
} else if (value > 33554431n) { //5 bytes
// noinspection JSCheckFunctionSignatures
return "100" + value.toString(2).padStart(34, '0') + exponent.toString(2).padStart(3, '0');
} else if (value > 131071n) { //4 bytes
// noinspection JSCheckFunctionSignatures
return "011" + value.toString(2).padStart(25, '0') + exponent.toString(2).padStart(4, '0');
} else if (value > 511n) { //3 bytes
// noinspection JSCheckFunctionSignatures
return "010" + value.toString(2).padStart(17, '0') + exponent.toString(2).padStart(4, '0');
} else { //2 bytes
// noinspection JSCheckFunctionSignatures
return "001" + value.toString(2).padStart(9, '0') + exponent.toString(2).padStart(4, '0');
}
}
/**
* Appends a binary string to the buffer data
* @param {string} bits Binary string of data
* @returns
*/
Precision.prototype.addBits = function (bits) {
if (!/^[01]+$/.test(bits))
throw "Invalid bin strign";
this._bits += bits;
return this;
}
/**
* Appends a hexadecimal string to the buffer data
* @param {string} hex Hexadecimal string of data
* @returns
*/
Precision.prototype.addHex = function (hex) {
if (!/^[0-9a-fA-F]+$/.test(hex))
throw "Invalid hex strign";
for (var char of hex) {
switch (char) {
case '0': this._bits += "0000"; break;
case '1': this._bits += "0001"; break;
case '2': this._bits += "0010"; break;
case '3': this._bits += "0011"; break;
case '4': this._bits += "0100"; break;
case '5': this._bits += "0101"; break;
case '6': this._bits += "0110"; break;
case '7': this._bits += "0111"; break;
case '8': this._bits += "1000"; break;
case '9': this._bits += "1001"; break;
case 'a': this._bits += "1010"; break;
case 'b': this._bits += "1011"; break;
case 'c': this._bits += "1100"; break;
case 'd': this._bits += "1101"; break;
case 'e': this._bits += "1110"; break;
case 'f': this._bits += "1111"; break;
}
}
return this;
}
/**
* Appends a buffer to the buffer data
* @param {Buffer} buffer Buffer object of data
* @returns
*/
Precision.prototype.addBuffer = function (buffer) {
for (var i = 0; i < buffer.length; i++)
this._bits += buffer[i].toString(2).padStart(8, "0");
return this;
}
/**
* Appends an integer to the buffer data with the desired size
* @param {*} integer Integer
* @param {*} size Size on bits of the integer
* @returns
*/
Precision.prototype.addInteger = function (integer, size) {
if (integer < 0) throw "Invalid positive integer";
if (integer >= Math.pow(2, size)) throw "Size is too short for integer";
this._bits += integer.toString(2).padStart(size, '0');
return this;
}
/**
* Appends an integer to the buffer data in the Bitcoin's precision encoding
* @param {Number} integer Integer number
* @returns
*/
Precision.prototype.addPrecision = function (integer) {
var bits = Precision.precision(integer);
this._bits += bits;
return this;
}
/**
* Returns a buffer representation of the data stored in the object
* @returns {Buffer}
*/
Precision.prototype.toBuffer = function () {
var missing = 8 - this._bits.length % 8;
if (missing !== 8) {
var extra = "";
while (missing != 0) {
extra += "0";
missing--;
}
this._bits = extra + this._bits;
}
var ans = Buffer.alloc(this._bits.length / 8);
for (var i = 0; i < ans.length; i++) {
ans[i] = parseInt(this._bits.substr(i * 8, 8), 2);
}
return ans;
}
module.exports = Precision;