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>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.ciyam</groupId>
|
<groupId>org.ciyam</groupId>
|
||||||
<artifactId>AT</artifactId>
|
<artifactId>AT</artifactId>
|
||||||
<version>1.4.0</version>
|
<version>1.4.1</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<properties>
|
<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.math.BigDecimal;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import org.ciyam.at.API;
|
import org.ciyam.at.API;
|
||||||
import org.ciyam.at.ExecutionException;
|
import org.ciyam.at.ExecutionException;
|
||||||
@ -130,7 +126,7 @@ public class TestAPI extends API {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hook to be oveerridden
|
// Hook to be overridden
|
||||||
protected void preExecute(MachineState state) {
|
protected void preExecute(MachineState state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +136,29 @@ public class TestAPI extends API {
|
|||||||
return encodedAddress;
|
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) {
|
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);
|
String address = new String(encodedAddress, StandardCharsets.ISO_8859_1);
|
||||||
return address.replace("\0", "");
|
return address.replace("\0", "");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user