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 }