// Use strict "use strict"; // Classes // Base58 class class Base58 { // Public // Encode static encode(byteArray) { // Go through all leading zeros in the byte array var numberOfLeadingZeros = 0; while(numberOfLeadingZeros < byteArray["length"] && byteArray[numberOfLeadingZeros] === 0) { // Increment number of leading zeros ++numberOfLeadingZeros; } // Get buffer size var bufferSize = Math.ceil((byteArray["length"] - numberOfLeadingZeros) * Base58.BYTES_PER_LENGTH_IN_NEW_BASE); // Create buffer var buffer = (new Uint8Array(bufferSize)).fill(0); // Go through all bytes in the byte array after the leading zeros var length = 0; for(var i = numberOfLeadingZeros; i < byteArray["length"]; ++i) { // Get byte var byte = byteArray[i]; // Go through all base 58 components of the byte for(var j = 0, k = bufferSize - 1; (byte !== 0 || j < length) && k >= 0; ++j, --k) { // Include the current buffer value in the byte byte += (Common.BYTE_MAX_VALUE + 1) * buffer[k]; // Set value in the buffer buffer[k] = byte % Base58.NUMBER_BASE; // Update the byte byte = Math.floor(byte / Base58.NUMBER_BASE); } // Update length length = j; } // Go through all leading zeros in the buffer var bufferIndex = bufferSize - length; while(bufferIndex < buffer["length"] && buffer[bufferIndex] === 0) { // Increment buffer index ++bufferIndex; } // Set result to start with the number of leading zeros in base58 var result = Base58.CHARACTERS[0].repeat(numberOfLeadingZeros); // Go through all bytes in the buffer after the leading zeros for(; bufferIndex < buffer["length"]; ++bufferIndex) { // Append buffer's value in base58 to the result result += Base58.CHARACTERS[buffer[bufferIndex]]; } // Return result return result; } // Encode with checksum static encodeWithChecksum(byteArray) { // Get the checksum of the byte array var checksum = Base58.getChecksum(byteArray); // Return encoding the byte array with the checksum return Base58.encode(Common.mergeArrays([ // Byte array byteArray, // Checksum checksum ])); } // Decode static decode(base58String) { // Go through all leading zeros in base58 in the string var numberOfLeadingZeros = 0; while(numberOfLeadingZeros < base58String["length"] && base58String[numberOfLeadingZeros] === Base58.CHARACTERS[0]) { // Increment number of leading zeros ++numberOfLeadingZeros; } // Get buffer size var bufferSize = Math.ceil((base58String["length"] - numberOfLeadingZeros) * Base58.BYTES_PER_LENGTH_IN_OLD_BASE); // Crete buffer var buffer = (new Uint8Array(bufferSize)).fill(0); // Go through all characters in the string after the leading zeros in base58 var length = 0; for(var i = numberOfLeadingZeros; i < base58String["length"]; ++i) { // Get character as byte var byte = Base58.CHARACTERS.indexOf(base58String[i]); // Check if byte is invalid if(byte === Common.INDEX_NOT_FOUND) { // Throw error throw "Invalid base58 string."; } // Go through all base 58 components of the byte for(var j = 0, k = bufferSize - 1; (byte !== 0 || j < length) && k >= 0; ++j, --k) { // Include the current buffer value in the byte byte += Base58.NUMBER_BASE * buffer[k]; // Set value in the buffer buffer[k] = byte % (Common.BYTE_MAX_VALUE + 1); // Update the byte byte = Math.floor(byte / (Common.BYTE_MAX_VALUE + 1)); } // Update length length = j; } // Go through all leading zeros in the buffer var bufferIndex = bufferSize - length; while(bufferIndex < buffer["length"] && buffer[bufferIndex] === 0) { // Increment buffer index ++bufferIndex; } // Set result to start with the number of leading zeros var result = (new Uint8Array(numberOfLeadingZeros + bufferSize - bufferIndex)).fill(0); // Go through all bytes in the buffer after the leading zeros for(var i = 0; bufferIndex < buffer["length"]; ++i, ++bufferIndex) { // Append buffer's value to the result result[i + numberOfLeadingZeros] += buffer[bufferIndex]; } // Return result return result; } // Decode with checksum static decodeWithChecksum(base58String) { // Try try { // Decode the string var byteArray = Base58.decode(base58String); } // Catch errors catch(error) { // Throw error throw error; } // Check if the byte array doesn't include a checksum if(byteArray["length"] < Base58.CHECKSUM_LENGTH) { // Throw error throw "No checksum exists."; } // Otherwise else { // Get the checksum of the byte array without its checksum var checksum = Base58.getChecksum(byteArray.subarray(0, byteArray["length"] - Base58.CHECKSUM_LENGTH)); // Get the provided checksum from the byte array var providedChecksum = byteArray.subarray(byteArray["length"] - Base58.CHECKSUM_LENGTH); // Check if checksums don't match if(Common.arraysAreEqual(checksum, providedChecksum) === false) { // Throw error throw "Invalid checksum."; } // Otherwise else { // Return byte array without the checksum return byteArray.subarray(0, byteArray["length"] - Base58.CHECKSUM_LENGTH); } } } // Private // Get checksum static getChecksum(byteArray) { // Get a hash of the hash of the byte array var hash = new Uint8Array(sha256.arrayBuffer(new Uint8Array(sha256.arrayBuffer(byteArray)))); // Get the checksum from the hash var checksum = hash.subarray(0, Base58.CHECKSUM_LENGTH); // Return checksum return checksum; } // Characters static get CHARACTERS() { // Return characters return "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; } // Number base static get NUMBER_BASE() { // Return number base return 58; } // Bytes per length in new base static get BYTES_PER_LENGTH_IN_NEW_BASE() { // Return bytes per length in new base return Math.log(Common.BYTE_MAX_VALUE + 1) / Math.log(Base58.NUMBER_BASE); } // Bytes per length in old base static get BYTES_PER_LENGTH_IN_OLD_BASE() { // Return bytes per length in old base return Math.log(Base58.NUMBER_BASE) / Math.log(Common.BYTE_MAX_VALUE + 1); } // Checksum length static get CHECKSUM_LENGTH() { // Return checksum length return 4; } } // Main function // Set global object's base58 globalThis["Base58"] = Base58;