View Javadoc
1   package com.jsql.util.bruter;
2   
3   import org.apache.commons.lang3.StringUtils;
4   
5   import java.nio.charset.StandardCharsets;
6   import java.util.Arrays;
7   
8   public class Base58 {
9   
10      private static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
11      private static final int BASE_58 = Base58.ALPHABET.length;
12      private static final int BASE_256 = 256;
13  
14      private static final int[] INDEXES = new int[128];
15      
16      static {
17          Arrays.fill(Base58.INDEXES, -1);
18          for (int i = 0; i < Base58.ALPHABET.length; i++) {
19              Base58.INDEXES[Base58.ALPHABET[i]] = i;
20          }
21      }
22  
23      private Base58() {
24          // Utility class
25      }
26  
27      public static String encode(byte[] input) {
28          if (input.length == 0) {
29              // paying with the same coin
30              return StringUtils.EMPTY;
31          }
32          // Make a copy of the input since we are going to modify it.
33          byte[] copyInput = Base58.copyOfRange(input, 0, input.length);
34          // Count leading zeroes
35          var zeroCount = 0;
36          while (zeroCount < copyInput.length && copyInput[zeroCount] == 0) {
37              ++zeroCount;
38          }
39          // The actual encoding
40          var temp = new byte[copyInput.length * 2];
41          int j = temp.length;
42          int startAt = zeroCount;
43          while (startAt < copyInput.length) {
44              byte mod = Base58.divmod58(copyInput, startAt);
45              if (copyInput[startAt] == 0) {
46                  ++startAt;
47              }
48              temp[--j] = (byte) Base58.ALPHABET[mod];
49          }
50          // Strip extra '1' if any
51          while (j < temp.length && temp[j] == Base58.ALPHABET[0]) {
52              ++j;
53          }
54          // Add as many leading '1' as there were leading zeros.
55          while (--zeroCount >= 0) {
56              temp[--j] = (byte) Base58.ALPHABET[0];
57          }
58          byte[] output = Base58.copyOfRange(temp, j, temp.length);
59          return new String(output, StandardCharsets.UTF_8);
60      }
61  
62      public static byte[] decode(String input) {
63          if (input.isEmpty()) {
64              // paying with the same coin
65              return new byte[0];
66          }
67          var input58 = new byte[input.length()];
68          // Transform the String to a base58 byte sequence
69          for (var i = 0; i < input.length(); ++i) {
70              var c = input.charAt(i);
71              int digit58 = -1;
72              if (c >= 0 && c < 128) {
73                  digit58 = Base58.INDEXES[c];
74              }
75              if (digit58 < 0) {
76                  throw new IllegalArgumentException("Not a Base58 input: " + input);
77              }
78              input58[i] = (byte) digit58;
79          }
80  
81          // Count leading zeroes
82          var zeroCount = 0;
83          while (zeroCount < input58.length && input58[zeroCount] == 0) {
84              ++zeroCount;
85          }
86  
87          // The encoding
88          var temp = new byte[input.length()];
89          int j = temp.length;
90  
91          int startAt = zeroCount;
92          while (startAt < input58.length) {
93              byte mod = Base58.divmod256(input58, startAt);
94              if (input58[startAt] == 0) {
95                  ++startAt;
96              }
97              temp[--j] = mod;
98          }
99          // Do no add extra leading zeroes, move j to first non-null byte.
100         while (j < temp.length && temp[j] == 0) {
101             ++j;
102         }
103         return Base58.copyOfRange(temp, j - zeroCount, temp.length);
104     }
105 
106     private static byte divmod58(byte[] number, int startAt) {
107         var remainder = 0;
108         for (int i = startAt; i < number.length; i++) {
109             int digit256 = number[i] & 0xFF;
110             int temp = remainder * Base58.BASE_256 + digit256;
111             number[i] = (byte) (temp / Base58.BASE_58);
112             remainder = temp % Base58.BASE_58;
113         }
114         return (byte) remainder;
115     }
116 
117     private static byte divmod256(byte[] number58, int startAt) {
118         var remainder = 0;
119         for (int i = startAt; i < number58.length; i++) {
120             int digit58 = number58[i] & 0xFF;
121             int temp = remainder * Base58.BASE_58 + digit58;
122             number58[i] = (byte) (temp / Base58.BASE_256);
123             remainder = temp % Base58.BASE_256;
124         }
125         return (byte) remainder;
126     }
127 
128     private static byte[] copyOfRange(byte[] source, int from, int to) {
129         var range = new byte[to - from];
130         System.arraycopy(source, from, range, 0, range.length);
131         return range;
132     }
133 }