Last active
July 17, 2019 12:07
-
-
Save tidyoux/87e338b83df697b4fd0410c8df48845b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Arrays; | |
import java.io.*; | |
public class MoneroBase58 { | |
private static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray(); | |
private static final int[] INDEXES = new int[128]; | |
static { | |
Arrays.fill(INDEXES, -1); | |
for (int i = 0; i < ALPHABET.length; i++) { | |
INDEXES[ALPHABET[i]] = i; | |
} | |
} | |
public static byte[] decode(String input) throws IllegalArgumentException { | |
if (input.length() == 0) { | |
return new byte[0]; | |
} | |
final int unit = 11; | |
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); | |
final int round = input.length() / unit; | |
for (int i = 0; i < round; ++i) { | |
byte[] data = decodeBlock(input.substring(i*unit, (i+1)*unit)); | |
buffer.write(data, 0, data.length); | |
} | |
if (input.length() % unit > 0) { | |
byte[] data = decodeBlock(input.substring(round*unit)); | |
buffer.write(data, 0, data.length); | |
} | |
return buffer.toByteArray(); | |
} | |
private static int decodeSize(int n) { | |
switch (n) { | |
case 0: return 0; | |
case 2: return 1; | |
case 3: return 2; | |
case 5: return 3; | |
case 6: return 4; | |
case 7: return 5; | |
case 9: return 6; | |
case 10: return 7; | |
case 11: return 8; | |
default: return -1; | |
} | |
} | |
private static byte[] decodeBlock(String input) throws IllegalArgumentException { | |
int outSize = decodeSize(input.length()); | |
if (outSize < 0) { | |
throw new IllegalArgumentException(); | |
} | |
if (outSize == 0) { | |
return new byte[0]; | |
} | |
// Convert the base58-encoded ASCII chars to a base58 byte sequence (base58 digits). | |
byte[] input58 = new byte[input.length()]; | |
for (int i = 0; i < input.length(); ++i) { | |
char c = input.charAt(i); | |
int digit = c < 128 ? INDEXES[c] : -1; | |
if (digit < 0) { | |
throw new IllegalArgumentException(); | |
} | |
input58[i] = (byte) digit; | |
} | |
// Count leading zeros. | |
int zeros = 0; | |
while (zeros < input58.length && input58[zeros] == 0) { | |
++zeros; | |
} | |
// Convert base-58 digits to base-256 digits. | |
byte[] decoded = new byte[input.length()]; | |
int outputStart = decoded.length; | |
for (int inputStart = zeros; inputStart < input58.length; ) { | |
decoded[--outputStart] = divmod(input58, inputStart, 58, 256); | |
if (input58[inputStart] == 0) { | |
++inputStart; // optimization - skip leading zeros | |
} | |
} | |
// Return decoded data (including original number of leading zeros). | |
return Arrays.copyOfRange(decoded, decoded.length-outSize, decoded.length); | |
} | |
/** | |
* Divides a number, represented as an array of bytes each containing a single digit | |
* in the specified base, by the given divisor. The given number is modified in-place | |
* to contain the quotient, and the return value is the remainder. | |
* | |
* @param number the number to divide | |
* @param firstDigit the index within the array of the first non-zero digit | |
* (this is used for optimization by skipping the leading zeros) | |
* @param base the base in which the number's digits are represented (up to 256) | |
* @param divisor the number to divide by (up to 256) | |
* @return the remainder of the division operation | |
*/ | |
private static byte divmod(byte[] number, int firstDigit, int base, int divisor) { | |
// this is just long division which accounts for the base of the input digits | |
int remainder = 0; | |
for (int i = firstDigit; i < number.length; i++) { | |
int digit = (int) number[i] & 0xFF; | |
int temp = remainder * base + digit; | |
number[i] = (byte) (temp / divisor); | |
remainder = temp % divisor; | |
} | |
return (byte) remainder; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment