Browse Source

Merge pull request #78 from tlwr/master

Base58 operations
n1474335 8 years ago
parent
commit
701ea5890d
3 changed files with 169 additions and 0 deletions
  1. 2 0
      src/js/config/Categories.js
  2. 31 0
      src/js/config/OperationConfig.js
  3. 136 0
      src/js/operations/Base58.js

+ 2 - 0
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",

+ 31 - 0
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.<br><br>This operation decodes data from an ASCII string (with an alphabet of your choosing, presets included) back into its raw form.<br><br>e.g. <code>StV1DL6CwTryKyV</code> becomes <code>hello world</code><br><br>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&#8209;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.<br><br>This operation encodes data in an ASCII string (with an alphabet of your choosing, presets included).<br><br>e.g. <code>hello world</code> becomes <code>StV1DL6CwTryKyV</code><br><br>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,

+ 136 - 0
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();
+    },
+};