3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-13 02:35:52 +00:00

Utils: Add some checks to bigIntegerToBytes().

This commit is contained in:
Nicola Atzei 2017-07-12 13:43:33 +02:00 committed by Andreas Schildbach
parent 3890219540
commit 3cb1f6c6c5
2 changed files with 81 additions and 9 deletions

View File

@ -59,20 +59,34 @@ public class Utils {
private static BlockingQueue<Boolean> mockSleepQueue;
/**
* The regular {@link java.math.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.
*
* <p>
* The regular {@link java.math.BigInteger#toByteArray()} includes the sign bit of the number and
* might result in an extra byte addition. This method removes this extra byte.
* </p>
* <p>
* Assuming only positive numbers, it's possible to discriminate if an extra byte
* is added by checking if the first element of the array is 0 (0000_0000).
* Due to the minimal representation provided by BigInteger, it means that the bit sign
* is the least significant bit 0000_000<b>0</b> .
* Otherwise the representation is not minimal.
* For example, if the sign bit is 0000_00<b>0</b>0, then the representation is not minimal due to the rightmost zero.
* </p>
* @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) {
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;
checkArgument(b.signum() >= 0, "b must be positive or zero");
checkArgument(numBytes > 0, "numBytes must be positive");
byte[] src = b.toByteArray();
byte[] dest = new byte[numBytes];
boolean isFirstByteOnlyForSign = src[0] == 0;
int length = isFirstByteOnlyForSign ? src.length - 1 : src.length;
checkArgument(length <= numBytes, "The given number does not fit in " + numBytes);
int srcPos = isFirstByteOnlyForSign ? 1 : 0;
int destPos = numBytes - length;
System.arraycopy(src, srcPos, dest, destPos, length);
return dest;
}
public static void uint32ToByteArrayBE(long val, byte[] out, int offset) {

View File

@ -1,6 +1,7 @@
/*
* Copyright 2011 Thilo Planz
* Copyright 2014 Andreas Schildbach
* Copyright 2017 Nicola Atzei
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,6 +19,7 @@
package org.bitcoinj.core;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Date;
import org.junit.Test;
@ -61,4 +63,60 @@ public class UtilsTest {
assertEquals("2014-11-16T10:54:33Z", Utils.dateTimeFormat(1416135273781L));
assertEquals("2014-11-16T10:54:33Z", Utils.dateTimeFormat(new Date(1416135273781L)));
}
@Test(expected = IllegalArgumentException.class)
public void bigIntegerToBytes_convertNegativeNumber() {
BigInteger b = BigInteger.valueOf(-1);
Utils.bigIntegerToBytes(b, 32);
}
@Test(expected = IllegalArgumentException.class)
public void bigIntegerToBytes_convertWithNegativeLength() {
BigInteger b = BigInteger.valueOf(10);
Utils.bigIntegerToBytes(b, -1);
}
@Test(expected = IllegalArgumentException.class)
public void bigIntegerToBytes_convertWithZeroLength() {
BigInteger b = BigInteger.valueOf(10);
Utils.bigIntegerToBytes(b, 0);
}
@Test(expected = IllegalArgumentException.class)
public void bigIntegerToBytes_insufficientLength() {
BigInteger b = BigInteger.valueOf(0b1000__0000_0000); // base 2
Utils.bigIntegerToBytes(b, 1);
}
@Test
public void bigIntegerToBytes_convertZero() {
BigInteger b = BigInteger.valueOf(0);
byte[] expected = new byte[]{0b0000_0000};
byte[] actual = Utils.bigIntegerToBytes(b, 1);
assertTrue(Arrays.equals(expected, actual));
}
@Test
public void bigIntegerToBytes_singleByteSignFit() {
BigInteger b = BigInteger.valueOf(0b0000_1111);
byte[] expected = new byte[]{0b0000_1111};
byte[] actual = Utils.bigIntegerToBytes(b, 1);
assertTrue(Arrays.equals(expected, actual));
}
@Test
public void bigIntegerToBytes_paddedSingleByte() {
BigInteger b = BigInteger.valueOf(0b0000_1111);
byte[] expected = new byte[]{0, 0b0000_1111};
byte[] actual = Utils.bigIntegerToBytes(b, 2);
assertTrue(Arrays.equals(expected, actual));
}
@Test
public void bigIntegerToBytes_singleByteSignDoesNotFit() {
BigInteger b = BigInteger.valueOf(0b1000_0000); // 128 (2-compl does not fit in one byte)
byte[] expected = new byte[]{-128}; // -128 == 1000_0000 (compl-2)
byte[] actual = Utils.bigIntegerToBytes(b, 1);
assertTrue(Arrays.equals(expected, actual));
}
}