diff --git a/src/js/config/Categories.js b/src/js/config/Categories.js
index ab2a4689..2611f300 100755
--- a/src/js/config/Categories.js
+++ b/src/js/config/Categories.js
@@ -40,6 +40,8 @@ var Categories = [
"Show Base64 offsets",
"To Base32",
"From Base32",
+ "To Base58",
+ "From Base58",
"To Base",
"From Base",
"To HTML Entity",
diff --git a/src/js/config/OperationConfig.js b/src/js/config/OperationConfig.js
index aff017c6..09b029c9 100755
--- a/src/js/config/OperationConfig.js
+++ b/src/js/config/OperationConfig.js
@@ -164,6 +164,37 @@ var OperationConfig = {
},
]
},
+ "From Base58": {
+ description: "Base58 (similar to Base64) is a notation for encoding arbitrary byte data. It improves upon Base64 by removing easily misread characters (i.e. lI0O) to improve human readability.
This operation decodes data from an ASCII string (with an alphabet of your choosing, presets included) back into its raw form.
e.g. StV1DL6CwTryKyV
becomes hello world
Base58 is commonly used in cryptocurrencies (Bitcoin, Ripple, etc).",
+ run: Base58.runFrom,
+ inputType: "string",
+ outputType: "byteArray",
+ args: [
+ {
+ name: "Alphabet",
+ type: "editableOption",
+ value: Base58.ALPHABET_OPTIONS
+ },
+ {
+ name: "Remove non‑alphabet chars",
+ type: "boolean",
+ value: Base58.REMOVE_NON_ALPH_CHARS
+ }
+ ]
+ },
+ "To Base58": {
+ description: "Base58 (similar to Base64) is a notation for encoding arbitrary byte data. It improves upon Base64 by removing easily misread characters (i.e. lI0O) to improve human readability.
This operation encodes data in an ASCII string (with an alphabet of your choosing, presets included).
e.g. hello world
becomes StV1DL6CwTryKyV
Base58 is commonly used in cryptocurrencies (Bitcoin, Ripple, etc).",
+ run: Base58.runTo,
+ inputType: "byteArray",
+ outputType: "string",
+ args: [
+ {
+ name: "Alphabet",
+ type: "editableOption",
+ value: Base58.ALPHABET_OPTIONS
+ },
+ ]
+ },
"From Base32": {
description: "Base32 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers. It uses a smaller set of characters than Base64, usually the uppercase alphabet and the numbers 2 to 7.",
run: Base64.runFrom32,
diff --git a/src/js/operations/Base58.js b/src/js/operations/Base58.js
new file mode 100755
index 00000000..c76ce6ee
--- /dev/null
+++ b/src/js/operations/Base58.js
@@ -0,0 +1,136 @@
+/**
+ * Base58 operations.
+ *
+ * @author tlwr [toby@toby.codes]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ *
+ * @namespace
+ */
+var Base58 = {
+
+
+ /**
+ * @constant
+ * @default
+ */
+ ALPHABET_OPTIONS: [
+ {
+ name: "Bitcoin",
+ value: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
+ },
+ {
+ name: "Ripple",
+ value: "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz",
+ },
+ ],
+
+
+ /**
+ * @constant
+ * @default
+ */
+ REMOVE_NON_ALPH_CHARS: true,
+
+
+ /**
+ * To Base58 operation.
+ *
+ * @param {byteArray} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ runTo: function(input, args) {
+ var alphabet = args[0] || Base58.ALPHABET_OPTIONS[0].value;
+
+ if (alphabet.length !== 58 ||
+ [].unique.call(alphabet).length !== 58) {
+ throw ("Error: alphabet must be of length 58");
+ }
+
+ if (input.length === 0) return "";
+
+ var result = [0];
+
+ input.forEach(function(b) {
+ var carry = (result[0] << 8) + b;
+ result[0] = carry % 58;
+ carry = (carry / 58) | 0;
+
+ for (var i = 1; i < result.length; i++) {
+ carry += result[i] << 8;
+ result[i] = carry % 58;
+ carry = (carry / 58) | 0;
+ }
+
+ while (carry > 0) {
+ result.push(carry % 58);
+ carry = (carry / 58) | 0;
+ }
+ });
+
+ result = result.map(function(b) {
+ return alphabet[b];
+ }).reverse().join("");
+
+ while (result.length < input.length) {
+ result = alphabet[0] + result;
+ }
+
+ return result;
+ },
+
+
+ /**
+ * From Base58 operation.
+ *
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {byteArray}
+ */
+ runFrom: function(input, args) {
+ var alphabet = args[0] || Base58.ALPHABET_OPTIONS[0].value;
+
+ if (alphabet.length !== 58 ||
+ [].unique.call(alphabet).length !== 58) {
+ throw ("Alphabet must be of length 58");
+ }
+
+ var removeNonAlphaChars = args[1];
+ if (removeNonAlphaChars === undefined)
+ removeNonAlphaChars = true;
+
+ if (input.length === 0) return [];
+
+ var result = [0];
+
+ [].forEach.call(input, function(c, charIndex) {
+ var index = alphabet.indexOf(c);
+
+ if (index === -1) {
+ if (removeNonAlphaChars) {
+ return;
+ } else {
+ throw ("Char " + c + " not in alphabet");
+ }
+ }
+
+ var carry = result[0] * 58 + index;
+ result[0] = carry & 0xFF;
+ carry = carry >> 8;
+
+ for (var i = 1; i < result.length; i++) {
+ carry += result[i] * 58;
+ result[i] = carry & 0xFF;
+ carry = carry >> 8;
+ }
+
+ while (carry > 0) {
+ result.push(carry & 0xFF);
+ carry = carry >> 8;
+ }
+ });
+
+ return result.reverse();
+ },
+};