Coverage Summary for Class: ByteUtil (org.ethereum.util)
Class |
Class, %
|
Method, %
|
Line, %
|
ByteUtil |
100%
(1/1)
|
36.2%
(17/47)
|
32.9%
(70/213)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2017 RSK Labs Ltd.
4 * (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 package org.ethereum.util;
21
22 import org.bouncycastle.util.encoders.Hex;
23 import org.ethereum.db.ByteArrayWrapper;
24
25 import javax.annotation.Nonnull;
26 import javax.annotation.Nullable;
27 import java.math.BigInteger;
28 import java.nio.ByteBuffer;
29 import java.util.Arrays;
30 import java.util.HashSet;
31 import java.util.Objects;
32 import java.util.Set;
33
34 public class ByteUtil {
35
36 private ByteUtil() {
37 }
38
39 public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
40 private static final byte[] ZERO_BYTE_ARRAY = new byte[]{0};
41
42 /**
43 * Creates a copy of bytes and appends b to the end of it
44 */
45 public static byte[] appendByte(byte[] bytes, byte b) {
46 byte[] result = Arrays.copyOf(bytes, bytes.length + 1);
47 result[result.length - 1] = b;
48 return result;
49 }
50
51 public static byte[] cloneBytes(byte[] bytes) {
52 if (bytes == null) {
53 return EMPTY_BYTE_ARRAY;
54 }
55
56 return Arrays.copyOf(bytes, bytes.length);
57 }
58
59 /**
60 * Adds leading zeros to a {@code src} byte array to have at least {@code len} length.
61 *
62 * @param src a source byte array
63 * @param len the minimum length of the final byte array with leading zeros.
64 * @return byte array with leading zeros.
65 */
66 public static byte[] toBytesWithLeadingZeros(byte[] src, int len) {
67 if (len < 0) {
68 throw new IllegalArgumentException("len");
69 }
70
71 if (src == null || len <= src.length) {
72 return src;
73 }
74
75 byte[] dest = new byte[len];
76 int start = len - src.length;
77 System.arraycopy(src, 0, dest, start, src.length);
78
79 return dest;
80 }
81
82 /**
83 * The regular {@link java.math.BigInteger#toByteArray()} method isn't quite what we often need:
84 * it appends a leading zero to indicate that the number is positive and may need padding.
85 *
86 * @param b the integer to format into a byte array
87 * @param numBytes the desired size of the resulting byte array
88 * @return numBytes byte long array.
89 */
90 public static byte[] bigIntegerToBytes(BigInteger b, int numBytes) {
91 if (b == null) {
92 return EMPTY_BYTE_ARRAY;
93 }
94 byte[] bytes = new byte[numBytes];
95 byte[] biBytes = b.toByteArray();
96 int start = (biBytes.length == numBytes + 1) ? 1 : 0;
97 int length = Math.min(biBytes.length, numBytes);
98 System.arraycopy(biBytes, start, bytes, numBytes - length, length);
99 return bytes;
100 }
101
102 /**
103 * Omitting sign indication byte.
104 * <br><br>
105 * Instead of {@link org.bouncycastle.util.BigIntegers#asUnsignedByteArray(BigInteger)}
106 * <br>we use this custom method to avoid an empty array in case of BigInteger.ZERO
107 *
108 * @param value - any big integer number. A <code>null</code>-value will return <code>null</code>
109 * @return A byte array without a leading zero byte if present in the signed encoding.
110 * BigInteger.ZERO will return an array with length 1 and byte-value 0.
111 */
112 public static byte[] bigIntegerToBytes(BigInteger value) {
113 if (value == null) {
114 return EMPTY_BYTE_ARRAY;
115 }
116
117 byte[] data = value.toByteArray();
118
119 if (data.length != 1 && data[0] == 0) {
120 byte[] tmp = new byte[data.length - 1];
121 System.arraycopy(data, 1, tmp, 0, tmp.length);
122 data = tmp;
123 }
124 return data;
125 }
126
127 /**
128 * Parses fixed number of bytes starting from {@code offset} in {@code input} array.
129 * If {@code input} has not enough bytes return array will be right padded with zero bytes.
130 * I.e. if {@code offset} is higher than {@code input.length} then zero byte array of length {@code len} will be returned
131 */
132 public static byte[] parseBytes(byte[] input, int offset, int len) {
133
134 if (offset >= input.length || len == 0) {
135 return EMPTY_BYTE_ARRAY;
136 }
137
138 byte[] bytes = new byte[len];
139 System.arraycopy(input, offset, bytes, 0, Math.min(input.length - offset, len));
140 return bytes;
141 }
142
143 /**
144 * Parses 32-bytes word from given input.
145 * Uses {@link #parseBytes(byte[], int, int)} method,
146 * thus, result will be right-padded with zero bytes if there is not enough bytes in {@code input}
147 *
148 * @param idx an index of the word starting from {@code 0}
149 */
150 public static byte[] parseWord(byte[] input, int idx) {
151 return parseBytes(input, 32 * idx, 32);
152 }
153
154 /**
155 * Parses 32-bytes word from given input.
156 * Uses {@link #parseBytes(byte[], int, int)} method,
157 * thus, result will be right-padded with zero bytes if there is not enough bytes in {@code input}
158 *
159 * @param idx an index of the word starting from {@code 0}
160 * @param offset an offset in {@code input} array to start parsing from
161 */
162 public static byte[] parseWord(byte[] input, int offset, int idx) {
163 return parseBytes(input, offset + 32 * idx, 32);
164 }
165
166 /**
167 * Returns the amount of nibbles that match each other from 0 ...
168 * amount will never be larger than smallest input
169 *
170 * @param a - first input
171 * @param b - second input
172 * @return Number of bytes that match
173 */
174 public static int matchingNibbleLength(byte[] a, byte[] b) {
175 int i = 0;
176 int length = a.length < b.length ? a.length : b.length;
177 while (i < length) {
178 if (a[i] != b[i]) {
179 return i;
180 }
181 i++;
182 }
183 return i;
184 }
185
186 /**
187 * Converts a long value into a byte array.
188 *
189 * @param val - long value to convert
190 * @return <code>byte[]</code> of length 8, representing the long value
191 */
192 public static byte[] longToBytes(long val) {
193 return ByteBuffer.allocate(8).putLong(val).array();
194 }
195
196 /**
197 * Converts a long value into a byte array.
198 *
199 * @param val - long value to convert
200 * @return decimal value with leading byte that are zeroes striped
201 */
202 public static byte[] longToBytesNoLeadZeroes(long val) {
203
204 // todo: improve performance by while strip numbers until (long >> 8 == 0)
205 byte[] data = ByteBuffer.allocate(8).putLong(val).array();
206
207 return stripLeadingZeroes(data);
208 }
209
210 /**
211 * Converts int value into a byte array.
212 *
213 * @param val - int value to convert
214 * @return <code>byte[]</code> of length 4, representing the int value
215 */
216 public static byte[] intToBytes(int val){
217 return ByteBuffer.allocate(4).putInt(val).array();
218 }
219
220 /**
221 * Converts a int value into a byte array.
222 *
223 * @param val - int value to convert
224 * @return value with leading byte that are zeroes striped
225 */
226 public static byte[] intToBytesNoLeadZeroes(int val){
227
228 if (val == 0) {
229 return EMPTY_BYTE_ARRAY;
230 }
231
232 int lenght = 0;
233
234 int tmpVal = val;
235 while (tmpVal != 0){
236 tmpVal = tmpVal >>> 8;
237 ++lenght;
238 }
239
240 byte[] result = new byte[lenght];
241
242 int index = result.length - 1;
243 while(val != 0){
244
245 result[index] = (byte)(val & 0xFF);
246 val = val >>> 8;
247 index -= 1;
248 }
249
250 return result;
251 }
252
253 /**
254 * Converts a byte-array into a hex String.<br>
255 * Works similar to {@link Hex#toHexString}, but allows for {@code null}.
256 *
257 * @param data - byte-array to convert to a hex-string
258 * @return hex representation of the data.<br>
259 * Returns an empty String if the input is <code>null</code>
260 *
261 * @see Hex#toHexString
262 */
263 @Nonnull
264 public static String toHexStringOrEmpty(@Nullable byte[] data) {
265 return data == null ? "" : toHexString(data);
266 }
267
268 /**
269 * Converts a byte-array into a hex String.<br>
270 * Works similar to {@link Hex#toHexString}. {@code data} cannot be {@code null}.
271 *
272 * @param data - byte-array to convert to a hex-string
273 * @return hex representation of the data.<br>
274 * @throws NullPointerException if {@code data} is {@code null}
275 *
276 * @see Hex#toHexString
277 */
278 @Nonnull
279 public static String toHexString(@Nonnull byte[] data) {
280 return Hex.toHexString(Objects.requireNonNull(data));
281 }
282
283 /**
284 * Converts a byte-array into a hex String.<br>
285 * Works similar to {@link Hex#toHexString}. {@code data} cannot be {@code null}.
286 *
287 * @param data - byte-array to convert to a hex-string
288 * @param off - initial offset of the subarray
289 * @param length - length of the subarray
290 * @return hex representation of the data.<br>
291 * @throws NullPointerException if {@code data} is {@code null}
292 *
293 * @see Hex#toHexString
294 */
295 @Nonnull
296 public static String toHexString(@Nonnull byte[] data, int off, int length) {
297 return Hex.toHexString(Objects.requireNonNull(data), off, length);
298 }
299
300 /**
301 * Calculate packet length
302 *
303 * @param msg byte[]
304 * @return byte-array with 4 elements
305 */
306 public static byte[] calcPacketLength(byte[] msg) {
307 int msgLen = msg.length;
308 return new byte[]{
309 (byte) ((msgLen >> 24) & 0xFF),
310 (byte) ((msgLen >> 16) & 0xFF),
311 (byte) ((msgLen >> 8) & 0xFF),
312 (byte) ((msgLen) & 0xFF)};
313 }
314
315 /**
316 * Cast hex encoded value from byte[] to int
317 *
318 * Limited to Integer.MAX_VALUE: 2^32-1 (4 bytes)
319 *
320 * @param b array contains the values
321 * @return unsigned positive int value.
322 */
323 public static int byteArrayToInt(byte[] b) {
324 if (b == null || b.length == 0) {
325 return 0;
326 }
327 return new BigInteger(1, b).intValue();
328 }
329
330 /**
331 * Cast from byte[] to long
332 * Limited to Long.MAX_VALUE: 2^63-1 (8 bytes)
333 * Will throw IlegalArgumentException if you pass
334 * a byte array with more than 8 bytes.
335 *
336 * @param b array contains the values
337 * @return unsigned positive long value.
338 */
339 public static long byteArrayToLong(byte[] b) {
340 if (b == null || b.length == 0) {
341 return 0;
342 }
343 // avoids overflows in the result
344 if (b.length > 8) {
345 throw new IllegalArgumentException("byte array can't have more than 8 bytes if it is to be cast to long");
346 }
347 long result = 0;
348 for (int i = 0; i < b.length; i++) {
349 result <<= 8;
350 result |= (b[i] & 0xFF);
351 }
352 return result;
353 }
354
355
356 /**
357 * Turn nibbles to a pretty looking output string
358 *
359 * Example. [ 1, 2, 3, 4, 5 ] becomes '\x11\x23\x45'
360 *
361 * @param nibbles - getting byte of data [ 04 ] and turning
362 * it to a '\x04' representation
363 * @return pretty string of nibbles
364 */
365 public static String nibblesToPrettyString(byte[] nibbles) {
366 StringBuilder builder = new StringBuilder();
367 for (byte nibble : nibbles) {
368 final String nibbleString = oneByteToHexString(nibble);
369 builder.append("\\x").append(nibbleString);
370 }
371 return builder.toString();
372 }
373
374 public static String oneByteToHexString(byte value) {
375 String retVal = Integer.toString(value & 0xFF, 16);
376 if (retVal.length() == 1) {
377 retVal = "0" + retVal;
378 }
379 return retVal;
380 }
381
382 /**
383 * Calculate the number of bytes need
384 * to encode the number
385 *
386 * @param val - number
387 * @return number of min bytes used to encode the number
388 */
389 public static int numBytes(String val) {
390 return new BigInteger(val).bitLength() / 8 + 1;
391 }
392
393 public static int firstNonZeroByte(byte[] data) {
394 for (int i = 0; i < data.length; ++i) {
395 if (data[i] != 0) {
396 return i;
397 }
398 }
399 return -1;
400 }
401
402 public static byte[] stripLeadingZeroes(byte[] data) {
403 return stripLeadingZeroes(data, ZERO_BYTE_ARRAY);
404 }
405
406 public static byte[] stripLeadingZeroes(byte[] data, byte[] valueForZero) {
407 if (data == null) {
408 return null;
409 }
410
411 final int firstNonZero = firstNonZeroByte(data);
412 switch (firstNonZero) {
413 case -1:
414 return valueForZero;
415
416 case 0:
417 return data;
418
419 default:
420 byte[] result = new byte[data.length - firstNonZero];
421 System.arraycopy(data, firstNonZero, result, 0, data.length - firstNonZero);
422
423 return result;
424 }
425 }
426
427 /**
428 * increment byte array as a number until max is reached
429 *
430 * @param bytes byte[]
431 * @return boolean
432 */
433 public static boolean increment(byte[] bytes) {
434 final int startIndex = 0;
435 int i;
436 for (i = bytes.length - 1; i >= startIndex; i--) {
437 bytes[i]++;
438 if (bytes[i] != 0) {
439 break;
440 }
441 }
442 // we return false when all bytes are 0 again
443 return (i >= startIndex || bytes[startIndex] != 0);
444 }
445
446 /**
447 * Utility function to copy a byte array into a new byte array with given size.
448 * If the src length is smaller than the given size, the result will be left-padded
449 * with zeros.
450 *
451 * @param value - a BigInteger with a maximum value of 2^256-1
452 * @return Byte array of given size with a copy of the <code>src</code>
453 */
454 public static byte[] copyToArray(BigInteger value) {
455 byte[] src = ByteUtil.bigIntegerToBytes(value);
456
457 if (Arrays.equals(src, EMPTY_BYTE_ARRAY)) {
458 throw new NullPointerException();
459 }
460
461 byte[] dest = ByteBuffer.allocate(32).array();
462 System.arraycopy(src, 0, dest, dest.length - src.length, src.length);
463 return dest;
464 }
465
466 public static ByteArrayWrapper wrap(byte[] data) {
467 return new ByteArrayWrapper(data);
468 }
469
470 public static byte[] setBit(byte[] data, int pos, int val) {
471
472 if ((data.length * 8) - 1 < pos) {
473 throw new Error("outside byte array limit, pos: " + pos);
474 }
475
476 int posByte = data.length - 1 - (pos) / 8;
477 int posBit = (pos) % 8;
478 byte setter = (byte) (1 << (posBit));
479 byte toBeSet = data[posByte];
480 byte result;
481 if (val == 1) {
482 result = (byte) (toBeSet | setter);
483 } else {
484 result = (byte) (toBeSet & ~setter);
485 }
486
487 data[posByte] = result;
488 return data;
489 }
490
491 public static int getBit(byte[] data, int pos) {
492
493 if ((data.length * 8) - 1 < pos) {
494 throw new Error("outside byte array limit, pos: " + pos);
495 }
496
497 int posByte = data.length - 1 - pos / 8;
498 int posBit = pos % 8;
499 byte dataByte = data[posByte];
500 return Math.min(1, (dataByte & 0xff & (1 << (posBit))));
501 }
502
503 public static byte[] and(byte[] b1, byte[] b2) {
504 if (b1.length != b2.length) {
505 throw new RuntimeException("Array sizes differ");
506 }
507 byte[] ret = new byte[b1.length];
508 for (int i = 0; i < ret.length; i++) {
509 ret[i] = (byte) (b1[i] & b2[i]);
510 }
511 return ret;
512 }
513
514 public static byte[] or(byte[] b1, byte[] b2) {
515 if (b1.length != b2.length) {
516 throw new RuntimeException("Array sizes differ");
517 }
518 byte[] ret = new byte[b1.length];
519 for (int i = 0; i < ret.length; i++) {
520 ret[i] = (byte) (b1[i] | b2[i]);
521 }
522 return ret;
523 }
524
525 @java.lang.SuppressWarnings("squid:S3034")
526 public static byte[] shiftLeft(byte[] byteArray, int shiftBitCount) {
527 // Code taken from the Apache 2 licensed library
528 // https://github.com/patrickfav/bytes-java/blob/master/src/main/java/at/favre/lib/bytes/Util.java
529 final int shiftMod = shiftBitCount % 8;
530 final byte carryMask = (byte) ((1 << shiftMod) - 1);
531 final int offsetBytes = (shiftBitCount / 8);
532
533 int sourceIndex;
534 for (int i = 0; i < byteArray.length; i++) {
535 sourceIndex = i + offsetBytes;
536 if (sourceIndex >= byteArray.length) {
537 byteArray[i] = 0;
538 } else {
539 byte src = byteArray[sourceIndex];
540 byte dst = (byte) (src << shiftMod);
541 if (sourceIndex + 1 < byteArray.length) {
542 dst |= byteArray[sourceIndex + 1] >>> (8 - shiftMod) & carryMask;
543 }
544 byteArray[i] = dst;
545 }
546 }
547 return byteArray;
548 }
549
550 @java.lang.SuppressWarnings("squid:S3034")
551 public static byte[] shiftRight(byte[] byteArray, int shiftBitCount) {
552 // Code taken from the Apache 2 licensed library
553 // https://github.com/patrickfav/bytes-java/blob/master/src/main/java/at/favre/lib/bytes/Util.java
554 final int shiftMod = shiftBitCount % 8;
555 final byte carryMask = (byte) (0xFF << (8 - shiftMod));
556 final int offsetBytes = (shiftBitCount / 8);
557
558 int sourceIndex;
559 for (int i = byteArray.length - 1; i >= 0; i--) {
560 sourceIndex = i - offsetBytes;
561 if (sourceIndex < 0) {
562 byteArray[i] = 0;
563 } else {
564 byte src = byteArray[sourceIndex];
565 byte dst = (byte) ((0xff & src) >>> shiftMod);
566 if (sourceIndex - 1 >= 0) {
567 dst |= byteArray[sourceIndex - 1] << (8 - shiftMod) & carryMask;
568 }
569 byteArray[i] = dst;
570 }
571 }
572 return byteArray;
573 }
574
575 /**
576 * @param arrays - arrays to merge
577 * @return - merged array
578 */
579 public static byte[] merge(byte[]... arrays) {
580 int count = 0;
581 for (byte[] array: arrays) {
582 count += array.length;
583 }
584
585 // Create new array and copy all array contents
586 byte[] mergedArray = new byte[count];
587 int start = 0;
588 for (byte[] array: arrays) {
589 System.arraycopy(array, 0, mergedArray, start, array.length);
590 start += array.length;
591 }
592 return mergedArray;
593 }
594
595 public static boolean isSingleZero(byte[] array){
596 return (array.length == 1 && array[0] == 0);
597 }
598
599 public static boolean isAllZeroes(byte[] array) {
600 for (byte b : array) {
601 if (b != 0) {
602 return false;
603 }
604 }
605
606 return true;
607 }
608
609 public static <T> Set<T> difference(Set<T> setA, Set<T> setB){
610
611 Set<T> temp = new HashSet<>(setA);
612 temp.removeAll(setB);
613 return temp;
614 }
615
616 public static int length(byte[]... bytes) {
617 int result = 0;
618 for (byte[] array : bytes) {
619 result += (array == null) ? 0 : array.length;
620 }
621 return result;
622 }
623
624 public static short bigEndianToShort(byte[] bs) {
625 return bigEndianToShort(bs, 0);
626 }
627
628 public static short bigEndianToShort(byte[] bs, int off) {
629 int n = bs[off] << 8;
630 ++off;
631 n |= bs[off] & 0xFF;
632 return (short) n;
633 }
634
635 public static byte[] shortToBytes(short n) {
636 return ByteBuffer.allocate(2).putShort(n).array();
637 }
638
639 /**
640 * Returns a number of zero bits preceding the highest-order ("leftmost") one-bit
641 * interpreting input array as a big-endian integer value
642 */
643 public static int numberOfLeadingZeros(byte[] bytes) {
644
645 int i = firstNonZeroByte(bytes);
646
647 if (i == -1) {
648 return bytes.length * 8;
649 } else {
650 int byteLeadingZeros = Integer.numberOfLeadingZeros((int)bytes[i] & 0xff) - 24;
651 return i * 8 + byteLeadingZeros;
652 }
653 }
654
655 /**
656 * Returns a copy of original padded to the left with zeroes,
657 * or original if {@code original.length >= newLength}
658 */
659 public static byte[] leftPadBytes(@Nonnull byte[] original, int newLength) {
660 // the result array is larger than the modulus length,
661 // but this should never happen.
662 if (original.length >= newLength) {
663 return original;
664 }
665
666 // otherwise adjust result to the same length as the modulus has
667 byte[] copy = new byte[newLength];
668 System.arraycopy(original, 0, copy, newLength - original.length, original.length);
669 return copy;
670 }
671
672 public static boolean fastEquals(byte[] left, byte[] right) {
673 return FastByteComparisons.compareTo(
674 left, 0, left.length,
675 right, 0, right.length) == 0;
676 }
677 }