mirror of
https://github.com/Qortal/AT.git
synced 2025-02-01 03:32:13 +00:00
Improve TestAPI.decodeAddress(byte[]) to encode binary addresses into Base58 form.
Included Base58 library. Bumped version to v1.4.1
This commit is contained in:
parent
836ef215d4
commit
b39c0d58b8
@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.ciyam</groupId>
|
||||
<artifactId>AT</artifactId>
|
||||
<version>1.4.0</version>
|
||||
<version>1.4.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
|
218
Java/src/test/java/org/ciyam/at/test/Base58.java
Normal file
218
Java/src/test/java/org/ciyam/at/test/Base58.java
Normal file
@ -0,0 +1,218 @@
|
||||
/**
|
||||
* Copyright 2011 Google Inc.
|
||||
* Copyright 2013-2014 Ronald W Hoffman
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.ciyam.at.test;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Provides Base-58 encoding and decoding
|
||||
*/
|
||||
public class Base58 {
|
||||
|
||||
/** Alphabet used for encoding and decoding */
|
||||
|
||||
private static final String ALPHABET_STR = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
|
||||
private static final char[] ALPHABET =
|
||||
ALPHABET_STR.toCharArray();
|
||||
|
||||
/** Lookup index for US-ASCII characters (code points 0-127) */
|
||||
private static final int[] INDEXES = new int[128];
|
||||
static {
|
||||
for (int i=0; i<INDEXES.length; i++)
|
||||
INDEXES[i] = -1;
|
||||
for (int i=0; i<ALPHABET.length; i++)
|
||||
INDEXES[ALPHABET[i]] = i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a byte array as a Base58 string
|
||||
*
|
||||
* @param bytes Array to be encoded
|
||||
* @return Encoded string
|
||||
*/
|
||||
|
||||
public static String encode(byte[] bytes) {
|
||||
//
|
||||
// Nothing to do for an empty array
|
||||
//
|
||||
if (bytes.length == 0)
|
||||
return "";
|
||||
//
|
||||
// Make a copy of the input since we will be modifying it as we go along
|
||||
//
|
||||
byte[] input = Arrays.copyOf(bytes, bytes.length);
|
||||
//
|
||||
// Count the number of leading zeroes (we will need to prefix the encoded result
|
||||
// with this many zero characters)
|
||||
//
|
||||
int zeroCount = 0;
|
||||
while (zeroCount < input.length && input[zeroCount] == 0)
|
||||
zeroCount++;
|
||||
//
|
||||
// Encode the input starting with the first non-zero byte
|
||||
//
|
||||
int offset = zeroCount;
|
||||
byte[] encoded = new byte[input.length*2];
|
||||
int encodedOffset = encoded.length;
|
||||
while (offset < input.length) {
|
||||
byte mod = divMod58(input, offset);
|
||||
if (input[offset] == 0)
|
||||
offset++;
|
||||
encoded[--encodedOffset] = (byte)ALPHABET[mod];
|
||||
}
|
||||
//
|
||||
// Strip any leading zero values in the encoded result
|
||||
//
|
||||
while (encodedOffset < encoded.length && encoded[encodedOffset] == (byte)ALPHABET[0])
|
||||
encodedOffset++;
|
||||
//
|
||||
// Now add the number of leading zeroes that we found in the input array
|
||||
//
|
||||
for (int i=0; i<zeroCount; i++)
|
||||
encoded[--encodedOffset] = (byte)ALPHABET[0];
|
||||
//
|
||||
// Create the return string from the encoded bytes
|
||||
//
|
||||
String encodedResult;
|
||||
try {
|
||||
byte[] stringBytes = Arrays.copyOfRange(encoded, encodedOffset, encoded.length);
|
||||
encodedResult = new String(stringBytes, "US-ASCII");
|
||||
} catch (UnsupportedEncodingException exc) {
|
||||
encodedResult = ""; // Should never happen
|
||||
}
|
||||
return encodedResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a Base58 string
|
||||
*
|
||||
* @param string Encoded string
|
||||
* @return Decoded bytes
|
||||
* @throws NumberFormatException Invalid Base-58 encoded string
|
||||
*/
|
||||
public static byte[] decode(String string) {
|
||||
//
|
||||
// Nothing to do if we have an empty string
|
||||
//
|
||||
if (string.length() == 0)
|
||||
return null;
|
||||
//
|
||||
// Convert the input string to a byte sequence
|
||||
//
|
||||
byte[] input = new byte[string.length()];
|
||||
for (int i=0; i<string.length(); i++) {
|
||||
int codePoint = string.codePointAt(i);
|
||||
int digit = -1;
|
||||
if (codePoint>=0 && codePoint<INDEXES.length)
|
||||
digit = INDEXES[codePoint];
|
||||
if (digit < 0)
|
||||
throw new NumberFormatException(
|
||||
String.format("Illegal character %c at index %d",
|
||||
string.charAt(i), i));
|
||||
input[i] = (byte)digit;
|
||||
}
|
||||
//
|
||||
// Count the number of leading zero characters
|
||||
//
|
||||
int zeroCount = 0;
|
||||
while (zeroCount < input.length && input[zeroCount] == 0)
|
||||
zeroCount++;
|
||||
//
|
||||
// Convert from Base58 encoding starting with the first non-zero character
|
||||
//
|
||||
byte[] decoded = new byte[input.length];
|
||||
int decodedOffset = decoded.length;
|
||||
int offset = zeroCount;
|
||||
while (offset < input.length) {
|
||||
byte mod = divMod256(input, offset);
|
||||
if (input[offset] == 0)
|
||||
offset++;
|
||||
decoded[--decodedOffset] = mod;
|
||||
}
|
||||
//
|
||||
// Strip leading zeroes from the decoded result
|
||||
//
|
||||
while (decodedOffset < decoded.length && decoded[decodedOffset] == 0)
|
||||
decodedOffset++;
|
||||
//
|
||||
// Return the decoded result prefixed with the number of leading zeroes
|
||||
// that were in the original string
|
||||
//
|
||||
byte[] output = Arrays.copyOfRange(decoded, decodedOffset-zeroCount, decoded.length);
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide the current number by 58 and return the remainder. The input array
|
||||
* is updated for the next round.
|
||||
*
|
||||
* @param number Number array
|
||||
* @param offset Offset within the array
|
||||
* @return The remainder
|
||||
*/
|
||||
private static byte divMod58(byte[] number, int offset) {
|
||||
int remainder = 0;
|
||||
for (int i=offset; i<number.length; i++) {
|
||||
int digit = (int)number[i]&0xff;
|
||||
int temp = remainder*256 + digit;
|
||||
number[i] = (byte)(temp/58);
|
||||
remainder = temp%58;
|
||||
}
|
||||
return (byte)remainder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide the current number by 256 and return the remainder. The input array
|
||||
* is updated for the next round.
|
||||
*
|
||||
* @param number Number array
|
||||
* @param offset Offset within the array
|
||||
* @return The remainder
|
||||
*/
|
||||
private static byte divMod256(byte[] number, int offset) {
|
||||
int remainder = 0;
|
||||
for (int i=offset; i<number.length; i++) {
|
||||
int digit = (int)number[i]&0xff;
|
||||
int temp = remainder*58 + digit;
|
||||
number[i] = (byte)(temp/256);
|
||||
remainder = temp%256;
|
||||
}
|
||||
return (byte)remainder;
|
||||
}
|
||||
|
||||
public static String encode(BigInteger id) {
|
||||
byte[] array = id.toByteArray();
|
||||
return encode(array);
|
||||
}
|
||||
|
||||
public static BigInteger decodeBI(String input) {
|
||||
return new BigInteger(decode(input));
|
||||
}
|
||||
|
||||
public static String clean(String str)
|
||||
{
|
||||
return str.replaceAll("[^"+ALPHABET_STR+"]", "");
|
||||
}
|
||||
|
||||
public static boolean isExtraSymbols(String str)
|
||||
{
|
||||
return !clean(str).equals(str);
|
||||
}
|
||||
}
|
@ -2,11 +2,7 @@ package org.ciyam.at.test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.*;
|
||||
|
||||
import org.ciyam.at.API;
|
||||
import org.ciyam.at.ExecutionException;
|
||||
@ -130,7 +126,7 @@ public class TestAPI extends API {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Hook to be oveerridden
|
||||
// Hook to be overridden
|
||||
protected void preExecute(MachineState state) {
|
||||
}
|
||||
|
||||
@ -140,7 +136,29 @@ public class TestAPI extends API {
|
||||
return encodedAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns address based on passed bytes.
|
||||
* <p>
|
||||
* If any byte is non-ASCII-printable, except trailing zeros,
|
||||
* then we assume address needs Base58 encoding.
|
||||
* <p>
|
||||
* Otherwise, assume bytes contain literal address.
|
||||
*/
|
||||
public static String decodeAddress(byte[] encodedAddress) {
|
||||
int lastNonZeroIndex = -1;
|
||||
for (int i = encodedAddress.length - 1; i >= 0; --i) {
|
||||
byte b = encodedAddress[i];
|
||||
|
||||
if (b == 0 && lastNonZeroIndex == -1)
|
||||
continue;
|
||||
|
||||
if (lastNonZeroIndex == -1)
|
||||
lastNonZeroIndex = i;
|
||||
|
||||
if (b < 32 || b > 126)
|
||||
return Base58.encode(Arrays.copyOf(encodedAddress, lastNonZeroIndex + 1));
|
||||
}
|
||||
|
||||
String address = new String(encodedAddress, StandardCharsets.ISO_8859_1);
|
||||
return address.replace("\0", "");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user