io.nuls.core.parse.SerializeUtils Maven / Gradle / Ivy
/*
* MIT License
*
* Copyright (c) 2017-2018 nuls.io
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package io.nuls.core.parse;
import io.nuls.core.basic.NulsData;
import io.nuls.core.basic.VarInt;
import io.nuls.core.constant.ToolsConstant;
import io.nuls.core.crypto.Sha256Hash;
import io.nuls.core.exception.NulsRuntimeException;
import io.nuls.core.log.Log;
import io.nuls.core.model.ByteUtils;
import org.bouncycastle.crypto.digests.RIPEMD160Digest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.charset.Charset;
/**
* @author tag
*/
public class SerializeUtils {
public static final Charset CHARSET = Charset.forName(ToolsConstant.DEFAULT_ENCODING);
private static final int MAGIC_8 = 8;
private static final int MAGIC_0X80 = 0x80;
/**
* The string that prefixes all text messages signed using Bitcoin keys.
*/
public static final String SIGNED_MESSAGE_HEADER = "RiceChain Signed Message:\n";
public static final byte[] SIGNED_MESSAGE_HEADER_BYTES = SIGNED_MESSAGE_HEADER.getBytes(CHARSET);
/**
* MPI encoded numbers are produced by the OpenSSL BN_bn2mpi function. They consist of
* a 4 byte big endian length field, followed by the stated number of bytes representing
* the number in big endian format (with a sign bit).
*
* @param hasLength can be set to false if the given array is missing the 4 byte length field
*/
public static BigInteger decodeMPI(byte[] mpi, boolean hasLength) {
byte[] buf;
if (hasLength) {
int length = (int) readUint32BE(mpi, 0);
buf = new byte[length];
System.arraycopy(mpi, 4, buf, 0, length);
} else {
buf = mpi;
}
if (buf.length == 0) {
return BigInteger.ZERO;
}
boolean isNegative = (buf[0] & MAGIC_0X80) == MAGIC_0X80;
if (isNegative) {
buf[0] &= 0x7f;
}
BigInteger result = new BigInteger(buf);
return isNegative ? result.negate() : result;
}
/**
* MPI encoded numbers are produced by the OpenSSL BN_bn2mpi function. They consist of
* a 4 byte big endian length field, followed by the stated number of bytes representing
* the number in big endian format (with a sign bit).
*
* @param includeLength indicates whether the 4 byte length field should be included
*/
public static byte[] encodeMPI(BigInteger value, boolean includeLength) {
if (value.equals(BigInteger.ZERO)) {
if (!includeLength) {
return new byte[]{};
} else {
return new byte[]{0x00, 0x00, 0x00, 0x00};
}
}
boolean isNegative = value.signum() < 0;
if (isNegative) {
value = value.negate();
}
byte[] array = value.toByteArray();
int length = array.length;
if ((array[0] & MAGIC_0X80) == MAGIC_0X80) {
length++;
}
if (includeLength) {
byte[] result = new byte[length + 4];
System.arraycopy(array, 0, result, length - array.length + 3, array.length);
uint32ToByteArrayBE(length, result, 0);
if (isNegative) {
result[4] |= MAGIC_0X80;
}
return result;
} else {
byte[] result;
if (length != array.length) {
result = new byte[length];
System.arraycopy(array, 0, result, 1, array.length);
} else {
result = array;
}
if (isNegative) {
result[0] |= MAGIC_0X80;
}
return result;
}
}
/**
* Given a textual message, returns a byte buffer formatted as follows:
*
* [24] "Bitcoin Signed Message:\n" [message.length as a varint] message
*/
public static byte[] formatMessageForSigning(String message) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(SIGNED_MESSAGE_HEADER_BYTES.length);
bos.write(SIGNED_MESSAGE_HEADER_BYTES);
byte[] messageBytes = message.getBytes(CHARSET);
VarInt size = new VarInt(messageBytes.length);
bos.write(size.encode());
bos.write(messageBytes);
return bos.toByteArray();
} catch (IOException e) {
// Cannot happen.
throw new RuntimeException(e);
}
}
public static short readUint8LE(byte[] bytes, int offset) {
return (short) (bytes[offset] & 0xff);
}
/**
* Parse 2 bytes from the byte array (starting at the offset) as unsigned 16-bit integer in little endian format./从字节数组(以偏移量开始)解析2字节,以小端格式的无符号16位整数
*
* @param bytes 字节数组
* @param offset 偏移量(数组下标)
*/
public static int readUint16LE(byte[] bytes, int offset) {
return (bytes[offset] & 0xff) |
((bytes[offset + 1] & 0xff) << 8);
}
/**
* Parse 2 bytes from the byte array (starting at the offset) as unsigned 16-bit integer in big endian format./从字节数组(以偏移量开始)解析2字节,以大端格式的无符号32位整数
*
* @param bytes 字节数组
* @param offset 偏移量(数组下标)
*/
public static int readUint16BE(byte[] bytes, int offset) {
return ((bytes[offset] & 0xff) << 8) |
(bytes[offset + 1] & 0xff);
}
/**
* Parse 2 bytes from the byte array (starting at the offset) as unsigned 16-bit integer in little endian format.
* 从字节数组(以偏移量开始)解析2字节,以端格式的无符号16位整数
*
* @param bytes byte[]
* @param offset int偏移量
* @return int
*/
public static int readUint16(byte[] bytes, int offset) {
return (bytes[offset] & 0xff) |
((bytes[offset + 1] & 0xff) << 8);
}
/**
* Parse 4 bytes from the byte array (starting at the offset) as unsigned 32-bit integer in little endian format./从字节数组(以偏移量开始)解析4字节,以小端格式的无符号32位整数
*
* @param bytes 字节数组
* @param offset 偏移量(数组下标)
*/
public static long readUint32LE(byte[] bytes, int offset) {
return (bytes[offset] & 0xffL) |
((bytes[offset + 1] & 0xffL) << 8) |
((bytes[offset + 2] & 0xffL) << 16) |
((bytes[offset + 3] & 0xffL) << 24);
}
/**
* Parse 4 bytes from the byte array (starting at the offset) as unsigned 32-bit integer in little endian format./从字节数组(以偏移量开始)解析4字节,以小端格式的无符号32位整数
*
* @param bytes 字节数组
* @param offset 偏移量(数组下标)
*/
public static int readInt32LE(byte[] bytes, int offset) {
return (bytes[offset] & 0xff) |
((bytes[offset + 1] & 0xff) << 8) |
((bytes[offset + 2] & 0xff) << 16) |
((bytes[offset + 3] & 0xff) << 24);
}
/**
* Parse 4 bytes from the byte array (starting at the offset) as unsigned 32-bit integer in big endian format./从字节数组(以偏移量开始)解析4字节,以大端格式的无符号32位整数
*
* @param bytes 字节数组
* @param offset 偏移量(数组下标)
*/
public static long readUint32BE(byte[] bytes, int offset) {
return ((bytes[offset] & 0xffL) << 24) |
((bytes[offset + 1] & 0xffL) << 16) |
((bytes[offset + 2] & 0xffL) << 8) |
(bytes[offset + 3] & 0xffL);
}
/**
* Parse 4 bytes from the byte array (starting at the offset) as unsigned 32-bit integer in little endian format.
* 从字节数组(以偏移量开始)解析4字节,以端格式的无符号32位整数
*
* @param bytes byte[]
* @param offset int偏移量
* @return int
*/
public static long readUint32(byte[] bytes, int offset) {
return (bytes[offset] & 0xffL) |
((bytes[offset + 1] & 0xffL) << 8) |
((bytes[offset + 2] & 0xffL) << 16) |
((bytes[offset + 3] & 0xffL) << 24);
}
/**
* Parse 6 bytes from the byte array (starting at the offset) as unsigned 48-bit integer in little endian format.
* 从字节数组(以偏移量开始)解析6字节,以端格式的无符号48位整数
*
* @param bytes byte[]
* @param offset int偏移量
* @return int
*/
public static long readUint48(byte[] bytes, int offset) {
return (bytes[offset] & 0xffL) |
((bytes[offset + 1] & 0xffL) << 8) |
((bytes[offset + 2] & 0xffL) << 16) |
((bytes[offset + 3] & 0xffL) << 24) |
((bytes[offset + 4] & 0xffL) << 32) |
((bytes[offset + 5] & 0xffL) << 40);
}
/**
* Parse 8 bytes from the byte array (starting at the offset) as unsigned 64-bit integer in little endian format./从字节数组(以偏移量开始)解析8字节,以小端格式的无符号64位整数
*
* @param bytes 字节数组
* @param offset 偏移量(数组下标)
*/
public static long readInt64LE(byte[] bytes, int offset) {
return (bytes[offset] & 0xffL) |
((bytes[offset + 1] & 0xffL) << 8) |
((bytes[offset + 2] & 0xffL) << 16) |
((bytes[offset + 3] & 0xffL) << 24) |
((bytes[offset + 4] & 0xffL) << 32) |
((bytes[offset + 5] & 0xffL) << 40) |
((bytes[offset + 6] & 0xffL) << 48) |
((bytes[offset + 7] & 0xffL) << 56);
}
/**
* Parse 8 bytes from the byte array (starting at the offset) as unsigned 64-bit integer in little endian format.
* 从字节数组(以偏移量开始)解析8字节,以端格式的无符号64位整数
*
* @param bytes byte[]
* @param offset int偏移量
* @return int
*/
public static long readUint64(byte[] bytes, int offset) {
return (bytes[offset] & 0xffL) |
((bytes[offset + 1] & 0xffL) << 8) |
((bytes[offset + 2] & 0xffL) << 16) |
((bytes[offset + 3] & 0xffL) << 24) |
((bytes[offset + 4] & 0xffL) << 32) |
((bytes[offset + 5] & 0xffL) << 40) |
((bytes[offset + 6] & 0xffL) << 48) |
((bytes[offset + 7] & 0xffL) << 56);
}
/**
* int转byte[] (只转int数据四个字节中的两个字节)
*
* @param x int
* @return byte[]
*/
public static byte[] int16ToBytes(int x) {
byte[] bb = new byte[2];
bb[1] = (byte) (0xFF & x >> 8);
bb[0] = (byte) (0xFF & x);
return bb;
}
/**
* int转byte[]
*
* @param x int
* @return byte[]
*/
public static byte[] int32ToBytes(int x) {
byte[] bb = new byte[4];
bb[3] = (byte) (0xFF & x >> 24);
bb[2] = (byte) (0xFF & x >> 16);
bb[1] = (byte) (0xFF & x >> 8);
bb[0] = (byte) (0xFF & x);
return bb;
}
/**
* long数据转byte[](只转前6个字节)
*
* @param val long
* @return byte[]
*/
public static byte[] uint48ToBytes(long val) {
byte[] bytes = new byte[SerializeUtils.sizeOfUint48()];
bytes[0] = (byte) (0xFF & val);
bytes[1] = (byte) (0xFF & (val >> 8));
bytes[2] = (byte) (0xFF & (val >> 16));
bytes[3] = (byte) (0xFF & (val >> 24));
bytes[4] = (byte) (0xFF & (val >> 32));
bytes[5] = (byte) (0xFF & (val >> 40));
return bytes;
}
/**
* long数据转byte[]
*
* @param val long
* @return byte[]
*/
public static byte[] uint64ToByteArray(long val) {
byte[] out = new byte[8];
out[0] = (byte) (0xFF & val);
out[1] = (byte) (0xFF & (val >> 8));
out[2] = (byte) (0xFF & (val >> 16));
out[3] = (byte) (0xFF & (val >> 24));
out[4] = (byte) (0xFF & (val >> 32));
out[5] = (byte) (0xFF & (val >> 40));
out[6] = (byte) (0xFF & (val >> 48));
out[7] = (byte) (0xFF & (val >> 56));
return out;
}
/**
* Calculates RIPEMD160(SHA256(input)). This is used in Address calculations.
*
* @param input 字节数组
*/
public static byte[] sha256hash160(byte[] input) {
byte[] sha256 = Sha256Hash.hash(input);
RIPEMD160Digest digest = new RIPEMD160Digest();
digest.update(sha256, 0, sha256.length);
byte[] out = new byte[20];
digest.doFinal(out, 0);
return out;
}
/**
* The regular {@link BigInteger#toByteArray()} method isn't quite what we often need: it appends a
* leading zero to indicate that the number is positive and may need padding.
*
* @param b the integer to format into a byte array
* @param numBytes the desired size of the resulting byte array
* @return numBytes byte long array.
*/
public static byte[] bigIntegerToBytes(BigInteger b, int numBytes) {
if (b == null) {
return null;
}
byte[] bytes = new byte[numBytes];
byte[] biBytes = b.toByteArray();
int start = (biBytes.length == numBytes + 1) ? 1 : 0;
int length = Math.min(biBytes.length, numBytes);
System.arraycopy(biBytes, start, bytes, numBytes - length, length);
return bytes;
}
/**
* 将一个short型数据以小端格式存储到指定字节数组指定的偏移量的连续2个字节中
*
* @param val short数据
* @param out 存放short型数据的字节数组
* @param offset 偏移量
*/
public static void int16ToByteArrayLE(short val, byte[] out, int offset) {
out[offset] = (byte) (0xFF & val);
out[offset + 1] = (byte) (0xFF & (val >> 8));
}
/**
* 将一个Long型数据以大端格式存储到指定字节数组指定的偏移量的连续4个字节中
*
* @param val long数据
* @param out 存放Long型数据的字节数组
* @param offset 偏移量
*/
public static void uint32ToByteArrayBE(long val, byte[] out, int offset) {
out[offset] = (byte) (0xFF & (val >> 24));
out[offset + 1] = (byte) (0xFF & (val >> 16));
out[offset + 2] = (byte) (0xFF & (val >> 8));
out[offset + 3] = (byte) (0xFF & val);
}
/**
* 将一个Long型数据以小端格式存储到指定字节数组指定的偏移量的连续4个字节中
*
* @param val long数据
* @param out 存放Long型数据的字节数组
* @param offset 偏移量
*/
public static void uint32ToByteArrayLE(long val, byte[] out, int offset) {
out[offset] = (byte) (0xFF & val);
out[offset + 1] = (byte) (0xFF & (val >> 8));
out[offset + 2] = (byte) (0xFF & (val >> 16));
out[offset + 3] = (byte) (0xFF & (val >> 24));
}
/**
* 将一个int型数据以小端格式存储到指定字节数组指定的偏移量的连续4个字节中
*
* @param val int数据
* @param out 存放int型数据的字节数组
* @param offset 偏移量
*/
public static void int32ToByteArrayLE(int val, byte[] out, int offset) {
out[offset] = (byte) (0xFF & val);
out[offset + 1] = (byte) (0xFF & (val >> 8));
out[offset + 2] = (byte) (0xFF & (val >> 16));
out[offset + 3] = (byte) (0xFF & (val >> 24));
}
/**
* 将一个Long型数据以小端格式存储到指定字节数组指定的偏移量的连续8个字节中
*
* @param val long数据
* @param out 存放Long型数据的字节数组
* @param offset 偏移量
*/
public static void uint64ToByteArrayLE(long val, byte[] out, int offset) {
out[offset] = (byte) (0xFF & val);
out[offset + 1] = (byte) (0xFF & (val >> 8));
out[offset + 2] = (byte) (0xFF & (val >> 16));
out[offset + 3] = (byte) (0xFF & (val >> 24));
out[offset + 4] = (byte) (0xFF & (val >> 32));
out[offset + 5] = (byte) (0xFF & (val >> 40));
out[offset + 6] = (byte) (0xFF & (val >> 48));
out[offset + 7] = (byte) (0xFF & (val >> 56));
}
public static void uint8ToByteStreamLE(short val, OutputStream stream) throws IOException {
stream.write((short) (0xFF & val));
}
/**
* Write 2 bytes to the output stream as unsigned 16-bit short in little endian format./将2字节写入输出流作为无符号16位short型数据,以小端格式
*
* @param val short数据
* @param stream 输出流
*/
public static void int16ToByteStreamLE(short val, OutputStream stream) throws IOException {
stream.write((byte) (0xFF & val));
stream.write((byte) (0xFF & (val >> 8)));
}
/**
* Write 2 bytes to the output stream as unsigned 16-bit integer in little endian format./将2字节写入输出流作为无符号16位整数,以小端格式
*
* @param val int数据
* @param stream 输出流
*/
public static void uint16ToByteStreamLE(int val, OutputStream stream) throws IOException {
stream.write((int) (0xFF & val));
stream.write((int) (0xFF & (val >> 8)));
}
/**
* Write 4 bytes to the output stream as unsigned 32-bit long in little endian format./将4字节写入输出流作为无符号32位long型数据,以小端格式
*
* @param val long数据
* @param stream 输出流
*/
public static void uint32ToByteStreamLE(long val, OutputStream stream) throws IOException {
stream.write((int) (0xFF & val));
stream.write((int) (0xFF & (val >> 8)));
stream.write((int) (0xFF & (val >> 16)));
stream.write((int) (0xFF & (val >> 24)));
}
/**
* Write 8 bytes to the output stream as unsigned 64-bit long in little endian format./将8字节写入输出流作为无符号64位long型数据,以小端格式
*
* @param val long数据
* @param stream 输出流
*/
public static void int64ToByteStreamLE(long val, OutputStream stream) throws IOException {
stream.write((int) (0xFF & val));
stream.write((int) (0xFF & (val >> 8)));
stream.write((int) (0xFF & (val >> 16)));
stream.write((int) (0xFF & (val >> 24)));
stream.write((int) (0xFF & (val >> 32)));
stream.write((int) (0xFF & (val >> 40)));
stream.write((int) (0xFF & (val >> 48)));
stream.write((int) (0xFF & (val >> 56)));
}
/**
* Write 8 bytes to the output stream as unsigned 64-bit BigInteger in little endian format./将8字节写入输出流作为无符号64位BigInteger型数据,以小端格式
*
* @param val BigInteger数据
* @param stream 输出流
*/
public static void uint64ToByteStreamLE(BigInteger val, OutputStream stream) throws IOException {
byte[] bytes = val.toByteArray();
if (bytes.length > MAGIC_8) {
throw new RuntimeException("Input too large to encode into a uint64");
}
bytes = ByteUtils.reverseBytes(bytes);
stream.write(bytes);
if (bytes.length < MAGIC_8) {
for (int i = 0; i < MAGIC_8 - bytes.length; i++) {
stream.write(0);
}
}
}
/**
* 将Double类型数据写入输出流
*
* @param val BigInteger数据
* @param stream 输出流
*/
public static void doubleToByteStream(double val, OutputStream stream) throws IOException {
stream.write(ByteUtils.doubleToBytes(val));
}
public static int sizeOfDouble(Double val) {
return MAGIC_8;
}
/**
* 字符串转为byte[]的长度
*
* @param val String
* @return int
*/
public static int sizeOfString(String val) {
if (null == val) {
return 1;
}
byte[] bytes;
try {
bytes = val.getBytes(ToolsConstant.DEFAULT_ENCODING);
} catch (UnsupportedEncodingException e) {
Log.error(e.getMessage());
throw new NulsRuntimeException(e);
}
return sizeOfBytes(bytes);
}
/**
* 计算Long型数据占几个字节
*
* @param val Long
* @return int
*/
public static int sizeOfVarInt(Long val) {
return VarInt.sizeOf(val);
}
/**
* 获取Int16数据占的字节数
*
* @return int
*/
public static int sizeOfInt16() {
return 2;
}
/**
* 获取BigInteger数据占的字节数
*
* @return int
*/
public static int sizeOfBigInteger() {
return 32;
}
/**
* 获取Uint16数据占的字节数
*
* @return int
*/
public static int sizeOfUint16() {
return 2;
}
/**
* 获取Int32数据占的字节数
*
* @return int
*/
public static int sizeOfInt32() {
return 4;
}
/**
* 获取Uint32数据占的字节数
*
* @return int
*/
public static int sizeOfUint32() {
return 4;
}
/**
* 获取Unit48数据占的字节数
*
* @return int
*/
public static int sizeOfUint48() {
return ToolsConstant.INT48_VALUE_LENGTH;
}
/**
* 获取Int64数据占的字节数
*
* @return int
*/
public static int sizeOfInt64() {
return 8;
}
/**
* 获取指定Integer占用的最小字节数
*
* @param val Integer
* @return int
*/
public static int sizeOfVarInt(Integer val) {
return VarInt.sizeOf(val);
}
/**
* 获取Boolean数据占的字节数
*
* @return int
*/
public static int sizeOfBoolean() {
return 1;
}
/**
* 获取nonce数据占的字节数
*
* @return int
*/
public static int sizeOfNonce() {
return 8;
}
/**
* 获取byte[]占用的最小字节数(byte[]长度占用的最小字节数+byte[]长度)
*/
public static int sizeOfBytes(byte[] val) {
if (null == val) {
return 1;
}
return VarInt.sizeOf((val).length) + (val).length;
}
/**
* 获取NulsData对象所占字节长度
*
* @param val NulsData
* @return int
*/
public static int sizeOfNulsData(NulsData val) {
if (null == val) {
return ToolsConstant.PLACE_HOLDER.length;
}
int size = val.size();
return size == 0 ? 1 : size;
}
/**
* 根据字节数组生成对应的大整数
* Generate corresponding large integers from byte arrays
*
* @param array 小端序的字节数组/Small-endian byte array
* @return 大整数
*/
public static BigInteger bigIntegerFromBytes(byte[] array) {
array = arrayReverse(array);
return new BigInteger(array);
}
/**
* 将大整数转为字节数组,结果是小端序字节数组
* Converting large integers to byte arrays results in small endian byte arrays
*
* @param value 大整数、BigInteger
* @return 字节数组
*/
public static byte[] bigInteger2Bytes(BigInteger value) {
byte[] bytes = new byte[32];
byte[] oBytes = value.toByteArray();
oBytes = arrayReverse(oBytes);
if (oBytes.length > 32) {
throw new RuntimeException("The number is too large!");
}
System.arraycopy(oBytes, 0, bytes, 0, oBytes.length);
return bytes;
}
/**
* 数组反转工具方法,会返回一个顺序颠倒的新的字节数组
* The array inversion tool method returns a new byte array in reverse order
*
* @param bytes 需要反转的字节数组
* @return a new byte array in reverse order
*/
private static byte[] arrayReverse(byte[] bytes) {
int length = bytes.length;
byte[] array = new byte[length];
for (int x = 0; x < length; x++) {
array[x] = bytes[length - 1 - x];
}
return array;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy