1 package com.jsql.util.bruter;
2
3 import java.nio.charset.StandardCharsets;
4 import java.util.Arrays;
5
6 public class Base58 {
7
8 private static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
9 private static final int BASE_58 = ALPHABET.length;
10 private static final int BASE_256 = 256;
11
12 private static final int[] INDEXES = new int[128];
13
14 static {
15 Arrays.fill(INDEXES, -1);
16
17 for (int i = 0; i < ALPHABET.length; i++) {
18 INDEXES[ALPHABET[i]] = i;
19 }
20 }
21
22 private Base58() {
23
24 }
25
26 public static String encode(byte[] input) {
27
28 if (input.length == 0) {
29
30 return "";
31 }
32
33
34 byte[] copyInput = copyOfRange(input, 0, input.length);
35
36
37 var zeroCount = 0;
38 while (zeroCount < copyInput.length && copyInput[zeroCount] == 0) {
39 ++zeroCount;
40 }
41
42
43 var temp = new byte[copyInput.length * 2];
44 int j = temp.length;
45
46 int startAt = zeroCount;
47 while (startAt < copyInput.length) {
48
49 byte mod = divmod58(copyInput, startAt);
50 if (copyInput[startAt] == 0) {
51 ++startAt;
52 }
53
54 temp[--j] = (byte) ALPHABET[mod];
55 }
56
57
58 while (j < temp.length && temp[j] == ALPHABET[0]) {
59 ++j;
60 }
61
62
63 while (--zeroCount >= 0) {
64 temp[--j] = (byte) ALPHABET[0];
65 }
66
67 byte[] output = copyOfRange(temp, j, temp.length);
68
69 return new String(output, StandardCharsets.UTF_8);
70 }
71
72 public static byte[] decode(String input) {
73
74 if (input.isEmpty()) {
75
76 return new byte[0];
77 }
78
79 var input58 = new byte[input.length()];
80
81
82 for (var i = 0; i < input.length(); ++i) {
83
84 var c = input.charAt(i);
85
86 int digit58 = -1;
87 if (c >= 0 && c < 128) {
88 digit58 = INDEXES[c];
89 }
90
91 if (digit58 < 0) {
92 throw new IllegalArgumentException("Not a Base58 input: " + input);
93 }
94
95 input58[i] = (byte) digit58;
96 }
97
98
99 var zeroCount = 0;
100 while (zeroCount < input58.length && input58[zeroCount] == 0) {
101 ++zeroCount;
102 }
103
104
105 var temp = new byte[input.length()];
106 int j = temp.length;
107
108 int startAt = zeroCount;
109 while (startAt < input58.length) {
110
111 byte mod = divmod256(input58, startAt);
112 if (input58[startAt] == 0) {
113 ++startAt;
114 }
115
116 temp[--j] = mod;
117 }
118
119
120 while (j < temp.length && temp[j] == 0) {
121 ++j;
122 }
123
124 return copyOfRange(temp, j - zeroCount, temp.length);
125 }
126
127 private static byte divmod58(byte[] number, int startAt) {
128
129 var remainder = 0;
130 for (int i = startAt; i < number.length; i++) {
131
132 int digit256 = number[i] & 0xFF;
133 int temp = remainder * BASE_256 + digit256;
134
135 number[i] = (byte) (temp / BASE_58);
136
137 remainder = temp % BASE_58;
138 }
139
140 return (byte) remainder;
141 }
142
143 private static byte divmod256(byte[] number58, int startAt) {
144
145 var remainder = 0;
146 for (int i = startAt; i < number58.length; i++) {
147
148 int digit58 = number58[i] & 0xFF;
149 int temp = remainder * BASE_58 + digit58;
150
151 number58[i] = (byte) (temp / BASE_256);
152
153 remainder = temp % BASE_256;
154 }
155
156 return (byte) remainder;
157 }
158
159 private static byte[] copyOfRange(byte[] source, int from, int to) {
160
161 var range = new byte[to - from];
162 System.arraycopy(source, from, range, 0, range.length);
163
164 return range;
165 }
166 }