mirror of
https://github.com/transatoshi-mw/grin-web-wallet.git
synced 2025-10-06 15:52:47 +00:00
267 lines
6.7 KiB
JavaScript
Executable File
267 lines
6.7 KiB
JavaScript
Executable File
// 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;
|