Coverage Summary for Class: DataWord (org.ethereum.vm)
Class |
Class, %
|
Method, %
|
Line, %
|
DataWord |
100%
(1/1)
|
54.5%
(30/55)
|
48.5%
(94/194)
|
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
21 package org.ethereum.vm;
22
23 import com.fasterxml.jackson.annotation.JsonCreator;
24 import com.fasterxml.jackson.annotation.JsonValue;
25 import org.bouncycastle.util.Arrays;
26 import org.bouncycastle.util.encoders.Hex;
27 import org.ethereum.crypto.HashUtil;
28 import org.ethereum.util.ByteUtil;
29 import org.ethereum.util.FastByteComparisons;
30
31 import java.math.BigInteger;
32 import java.nio.ByteBuffer;
33 import java.nio.charset.StandardCharsets;
34
35 /**
36 * DataWord is the 32-byte array representation of a 256-bit number
37 * Calculations can be done on this word with other DataWords
38 *
39 * @author Roman Mandeleil
40 * @since 01.06.2014
41 */
42 public final class DataWord implements Comparable<DataWord> {
43 /**
44 * The number of bytes used to represent a DataWord
45 */
46 public static final int BYTES = 32;
47 private static final byte[] ZERO_DATA = new byte[BYTES];
48
49 /* Maximum value of the DataWord */
50 public static final BigInteger _2_256 = BigInteger.valueOf(2).pow(256);
51 public static final BigInteger MAX_VALUE = _2_256.subtract(BigInteger.ONE);
52 public static final DataWord ZERO = new DataWord(ZERO_DATA);
53 public static final DataWord ONE = valueOf(1);
54 public static final int MAX_POW = 256;
55
56 private final byte[] data;
57
58 /**
59 * Use this constructor for internal operations that don't need copying
60 */
61 private DataWord(byte[] data) {
62 if (data.length != BYTES) {
63 throw new IllegalArgumentException(String.format("A DataWord must be %d bytes long", BYTES));
64 }
65
66 this.data = data;
67 }
68
69 /**
70 * Returns a copy of the internal data in order to guarantee immutability
71 */
72 public byte[] getData() {
73 return Arrays.copyOf(data, data.length);
74 }
75
76 public byte[] getNoLeadZeroesData() {
77 byte[] noLeadZeroesData = ByteUtil.stripLeadingZeroes(data);
78 if (noLeadZeroesData == data) {
79 // in case the method returned the same object, return a copy to ensure immutability
80 return getData();
81 }
82
83 return noLeadZeroesData;
84 }
85
86 // This is a special method that returns the data as the repository requires it.
87 // A zero value is converted into a null (the storage cell is deleted).
88 public byte[] getByteArrayForStorage() {
89 return ByteUtil.stripLeadingZeroes(data, null);
90 }
91
92 public byte[] getLast20Bytes() {
93 return Arrays.copyOfRange(data, 12, data.length);
94 }
95
96 public BigInteger value() {
97 return new BigInteger(1, data);
98 }
99
100 /**
101 * Converts this DataWord to an int.
102 * DOES NOT THROW EXCEPTION ON OVERFLOW
103 * @return this DataWord converted to an int.
104 */
105 public int intValue() {
106 int intVal = 0;
107 // Assumes 32-byte data always
108 for (int i = data.length-4; i < data.length; i++)
109 {
110 intVal = (intVal << 8) + (data[i] & 0xff);
111 }
112
113 return intVal;
114 }
115
116 /**
117 * Converts this DataWord to an int, checking for lost information.
118 * If this DataWord is out of the possible range for an int result
119 * then an ArithmeticException is thrown.
120 *
121 * @return this DataWord converted to an int.
122 * @throws ArithmeticException - if this will not fit in an int.
123 */
124 public int intValueCheck() {
125 if (bitsOccupied()>31) {
126 throw new ArithmeticException();
127 }
128
129 return intValue();
130 }
131
132 /**
133 * In case of int overflow returns Integer.MAX_VALUE
134 * otherwise works as #intValue()
135 */
136 public int intValueSafe() {
137 if (occupyMoreThan(4)) {
138 return Integer.MAX_VALUE;
139 }
140
141 int intValue = intValue();
142 if (intValue < 0) {
143 return Integer.MAX_VALUE;
144 }
145 return intValue;
146 }
147
148 /**
149 * Converts this DataWord to a long.
150 * If data overflows, it will consider only the last 8 bytes
151 * @return this DataWord converted to a long.
152 */
153 public long longValue() {
154
155 long longVal = 0;
156 // Assumes 32-byte data always
157 for (int i = data.length-8; i < data.length; i++)
158 {
159 longVal = (longVal << 8) + (data[i] & 0xff);
160 }
161
162 return longVal;
163 }
164
165 /**
166 * In case of long overflow returns Long.MAX_VALUE
167 * otherwise works as #longValue()
168 */
169 public long longValueSafe() {
170 if (occupyMoreThan(8)) {
171 return Long.MAX_VALUE;
172 }
173
174 long longValue = longValue();
175 if (longValue < 0) {
176 return Long.MAX_VALUE;
177 }
178 return longValue;
179 }
180
181 public BigInteger sValue() {
182 return new BigInteger(data);
183 }
184
185 public String bigIntValue() {
186 return new BigInteger(data).toString();
187 }
188
189 public boolean isZero() {
190 for (int i = this.data.length-1; i>=0;i--) {
191 if (data[i] != 0) {
192 return false;
193 }
194 }
195 return true;
196 }
197
198 // only in case of signed operation
199 // when the number is explicit defined
200 // as negative
201 public boolean isNegative() {
202 int result = data[0] & 0x80;
203 return result == 0x80;
204 }
205
206 public DataWord and(DataWord w2) {
207 byte[] newdata = getData();
208
209 for (int i = 0; i < this.data.length; ++i) {
210 newdata[i] &= w2.data[i];
211 }
212
213 return new DataWord(newdata);
214 }
215
216 public DataWord or(DataWord w2) {
217 byte[] newdata = getData();
218
219 for (int i = 0; i < this.data.length; ++i) {
220 newdata[i] |= w2.data[i];
221 }
222
223 return new DataWord(newdata);
224 }
225
226 public DataWord xor(DataWord w2) {
227 byte[] newdata = getData();
228
229 for (int i = 0; i < this.data.length; ++i) {
230 newdata[i] ^= w2.data[i];
231 }
232
233 return new DataWord(newdata);
234 }
235
236 public DataWord bnot() {
237 byte[] newdata = new byte[BYTES];
238
239 for (int i = 0; i < this.data.length; ++i) {
240 newdata[i] = (byte) ~this.data[i];
241 }
242
243 return new DataWord(newdata);
244 }
245
246 // By : Holger
247 // From : http://stackoverflow.com/a/24023466/459349
248 public DataWord add(DataWord word) {
249 byte[] newdata = new byte[BYTES];
250
251 for (int i = 31, overflow = 0; i >= 0; i--) {
252 int v = (this.data[i] & 0xff) + (word.data[i] & 0xff) + overflow;
253 newdata[i] = (byte) v;
254 overflow = v >>> 8;
255 }
256
257 return new DataWord(newdata);
258 }
259
260 // TODO: mul can be done in more efficient way
261 // TODO: with shift left shift right trick
262 // TODO without BigInteger quick hack
263 public DataWord mul(DataWord word) {
264 BigInteger result = value().multiply(word.value());
265 return valueOf(result.and(MAX_VALUE));
266 }
267
268 // TODO: improve with no BigInteger
269 public DataWord div(DataWord word) {
270
271 if (word.isZero()) {
272 return DataWord.ZERO;
273 }
274
275 BigInteger result = value().divide(word.value());
276 return valueOf(result.and(MAX_VALUE));
277 }
278
279 // TODO: improve with no BigInteger
280 public DataWord sDiv(DataWord word) {
281 if (word.isZero()) {
282 return DataWord.ZERO;
283 }
284
285 BigInteger result = sValue().divide(word.sValue());
286 return valueOf(result.and(MAX_VALUE));
287 }
288
289 // TODO: improve with no BigInteger
290 public DataWord sub(DataWord word) {
291 BigInteger result = value().subtract(word.value());
292 return valueOf(result.and(MAX_VALUE));
293 }
294
295 // TODO: improve with no BigInteger
296 public DataWord exp(DataWord word) {
297 BigInteger result = value().modPow(word.value(), _2_256);
298 return valueOf(result);
299 }
300
301 // TODO: improve with no BigInteger
302 public DataWord mod(DataWord word) {
303 if (word.isZero()) {
304 return DataWord.ZERO;
305 }
306
307 BigInteger result = value().mod(word.value());
308 return valueOf(result.and(MAX_VALUE));
309 }
310
311 public DataWord sMod(DataWord word) {
312 if (word.isZero()) {
313 return DataWord.ZERO;
314 }
315
316 BigInteger result = sValue().abs().mod(word.sValue().abs());
317 result = (sValue().signum() == -1) ? result.negate() : result;
318
319 return valueOf(result.and(MAX_VALUE));
320 }
321
322 public DataWord addmod(DataWord word1, DataWord word2) {
323 if (word2.isZero()) {
324 return DataWord.ZERO;
325 }
326
327 BigInteger result = value().add(word1.value()).mod(word2.value());
328 return valueOf(result.and(MAX_VALUE));
329 }
330
331 public DataWord mulmod(DataWord word1, DataWord word2) {
332 if (word2.isZero()) {
333 return DataWord.ZERO;
334 }
335
336 BigInteger result = value().multiply(word1.value()).mod(word2.value());
337 return valueOf(result.and(MAX_VALUE));
338 }
339
340 /**
341 * Shift left, both this and input arg are treated as unsigned
342 * @param arg
343 * @return this << arg
344 */
345
346 public DataWord shiftLeft(DataWord arg) {
347 if (arg.compareTo(DataWord.valueOf(MAX_POW)) >= 0) {
348 return DataWord.ZERO;
349 }
350
351 byte[] bytes = ByteUtil.shiftLeft(this.getData(), arg.intValueSafe());
352
353 return new DataWord(bytes);
354 }
355
356 /**
357 * Shift right, both this and input arg are treated as unsigned
358 * @param arg
359 * @return this >> arg
360 */
361 public DataWord shiftRight(DataWord arg) {
362 if (arg.compareTo(DataWord.valueOf(MAX_POW)) >= 0) {
363 return DataWord.ZERO;
364 }
365
366 byte[] bytes = ByteUtil.shiftRight(this.getData(), arg.intValueSafe());
367 return new DataWord(bytes);
368 }
369
370 /**
371 * Shift right, this is signed, while input arg is treated as unsigned
372 * @param arg
373 * @return this >> arg
374 */
375 public DataWord shiftRightSigned(DataWord arg) {
376 // Taken from Pantheon implementation
377 // https://github.com/PegaSysEng/pantheon/blob/master/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/operations/SarOperation.java
378
379 if (arg.compareTo(DataWord.valueOf(MAX_POW)) >= 0) {
380 if (this.isNegative()) {
381 return valueOf(MAX_VALUE); // This should be 0xFFFFF......
382 } else {
383 return DataWord.ZERO;
384 }
385 }
386
387 byte[] bytes = ByteUtil.shiftRight(this.getData(), arg.intValueSafe());
388
389 if (isNegative()){
390 byte[] allBits = valueOf(MAX_VALUE).getData();
391 byte[] significantBits = ByteUtil.shiftLeft(allBits, 256 - arg.intValueSafe());
392 bytes = ByteUtil.or(bytes, significantBits);
393 }
394
395 return new DataWord(bytes);
396 }
397
398
399 @JsonValue
400 @Override
401 public String toString() {
402 return ByteUtil.toHexString(data);
403 }
404
405 public String toPrefixString() {
406
407 byte[] pref = getNoLeadZeroesData();
408 if (pref.length == 0) {
409 return "";
410 }
411
412 if (pref.length < 7) {
413 return ByteUtil.toHexString(pref);
414 }
415
416 return ByteUtil.toHexString(pref).substring(0, 6);
417 }
418
419 public String shortHex() {
420 String hexValue = ByteUtil.toHexString(getNoLeadZeroesData()).toUpperCase();
421 return "0x" + hexValue.replaceFirst("^0+(?!$)", "");
422 }
423
424 @Override
425 public boolean equals(Object o) {
426 if (this == o) {
427 return true;
428 }
429 if (o == null || getClass() != o.getClass()) {
430 return false;
431 }
432 return equalValue((DataWord) o);
433 }
434
435 public boolean equalValue(DataWord o) {
436 return java.util.Arrays.equals(data, o.data);
437
438 }
439
440 @Override
441 public int hashCode() {
442 return java.util.Arrays.hashCode(data);
443 }
444
445 @Override
446 public int compareTo(DataWord o) {
447 if (o == null || o.data == null) {
448 return -1;
449 }
450 int result = FastByteComparisons.compareTo(
451 data, 0, data.length,
452 o.data, 0, o.data.length
453 );
454
455 // Convert result into -1, 0 or 1 as is the convention
456 // SigNum uses floating point arithmetic. It should be faster
457 // to solve it in integer arithmetic
458 // return (int) Math.signum(result);
459 if (result<0) {
460 return -1;
461 } else if (result>0) {
462 return 1;
463 } else {
464 return 0;
465 }
466 }
467
468 public DataWord signExtend(byte k) {
469 byte[] newdata = getData();
470
471 if (0 > k || k > 31) {
472 throw new IndexOutOfBoundsException();
473 }
474
475 byte mask = (new BigInteger(newdata)).testBit((k * 8) + 7) ? (byte) 0xff : 0;
476
477 for (int i = 31; i > k; i--) {
478 newdata[31 - i] = mask;
479 }
480
481 return new DataWord(newdata);
482 }
483
484 public boolean occupyMoreThan(int n) {
485 return bytesOccupied()>n;
486 }
487
488 public int bytesOccupied() {
489 int firstNonZero = ByteUtil.firstNonZeroByte(data);
490 if (firstNonZero == -1) {
491 return 0;
492 }
493 return 31 - firstNonZero + 1;
494 }
495
496 public static int numberOfLeadingZeros(byte i) {
497 // UNTESTED: Needs unit testing
498 if (i == 0) {
499 return 8;
500 }
501 int n = 0;
502 int v = i;
503 if (v >>> 4 == 0) {
504 n += 4;
505 v <<= 4;
506 }
507 if (v >>> 6 == 0) {
508 n += 2;
509 v <<= 2;
510 }
511 if (v >>> 7 == 0) {
512 n += 1;
513 }
514
515 return n;
516 }
517
518 public static int numberOfTrailingNonZeros(byte i) {
519 return 8 - numberOfLeadingZeros(i);
520 }
521
522 public int bitsOccupied() {
523 int firstNonZero = ByteUtil.firstNonZeroByte(data);
524 if (firstNonZero == -1) {
525 return 0;
526 }
527
528 // TODO Replace/Update this class code with current EthereumJ version
529 return numberOfTrailingNonZeros(data[firstNonZero]) + ((31 - firstNonZero)<<3);
530 }
531
532 public boolean isHex(String hex) {
533 return ByteUtil.toHexString(data).equals(hex);
534 }
535
536 /**
537 * Will create a DataWord from the string value.
538 * @param value any string with a byte representation of 32 bytes or less
539 * @return a DataWord with the encoded string as the data, padded with zeroes if necessary
540 */
541 public static DataWord fromString(String value) {
542 return valueOf(value.getBytes(StandardCharsets.UTF_8));
543 }
544
545 /**
546 * Will create a Dataword from the keccack256 representation of the string value.
547 * @param value any streing with a byte representation of more than 32 bytes
548 * @return a DataWord with the hashed string as the data
549 */
550 public static DataWord fromLongString(String value) { return valueOf(HashUtil.keccak256(value.getBytes(StandardCharsets.UTF_8))); }
551
552 @JsonCreator
553 public static DataWord valueFromHex(String data) {
554 return valueOf(Hex.decode(data));
555 }
556
557 public static DataWord valueOf(int num) {
558 byte[] data = new byte[BYTES];
559 ByteBuffer.wrap(data).putInt(data.length - Integer.BYTES, num);
560 return valueOf(data);
561 }
562
563 public static DataWord valueOf(long num) {
564 byte[] data = new byte[BYTES];
565 ByteBuffer.wrap(data).putLong(data.length - Long.BYTES, num);
566 return valueOf(data);
567 }
568
569 public static DataWord valueOf(byte[] data) {
570 return valueOf(data, 0, data.length);
571 }
572
573 public static DataWord valueOf(byte[] data, int offset, int length) {
574 if (data == null || length == 0) {
575 return ZERO;
576 }
577
578 if (length > BYTES) {
579 throw new IllegalArgumentException(String.format("A DataWord must be %d bytes long", BYTES));
580 }
581
582 // if there is not enough data
583 // trailing zeros are assumed (this is required for PUSH opcode semantics)
584 byte[] copiedData = new byte[BYTES];
585 int dlen = Integer.min(length, data.length - offset);
586 System.arraycopy(data, offset, copiedData, BYTES - length, dlen);
587 return new DataWord(copiedData);
588 }
589
590 private static DataWord valueOf(BigInteger data) {
591 return new DataWord(ByteUtil.copyToArray(data));
592 }
593 }