Coverage Summary for Class: PrecompiledContracts (org.ethereum.vm)

Class Method, % Line, %
PrecompiledContracts 100% (3/3) 78.3% (54/69)
PrecompiledContracts$BigIntegerModexp 25% (2/8) 4.1% (2/49)
PrecompiledContracts$Blake2F 0% (0/3) 0% (0/30)
PrecompiledContracts$ECRecover 25% (1/4) 4% (1/25)
PrecompiledContracts$Identity 33.3% (1/3) 28.6% (2/7)
PrecompiledContracts$PrecompiledContract 33.3% (1/3) 33.3% (1/3)
PrecompiledContracts$Ripempd160 33.3% (1/3) 10% (1/10)
PrecompiledContracts$Sha256 33.3% (1/3) 12.5% (1/8)
Total 33.3% (10/30) 30.8% (62/201)


1 package org.ethereum.vm; 2 /* 3  * This file is part of RskJ 4  * Copyright (C) 2017 RSK Labs Ltd. 5  * (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>) 6  * 7  * This program is free software: you can redistribute it and/or modify 8  * it under the terms of the GNU Lesser General Public License as published by 9  * the Free Software Foundation, either version 3 of the License, or 10  * (at your option) any later version. 11  * 12  * This program is distributed in the hope that it will be useful, 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15  * GNU Lesser General Public License for more details. 16  * 17  * You should have received a copy of the GNU Lesser General Public License 18  * along with this program. If not, see <http://www.gnu.org/licenses/>. 19  */ 20  21  22 import co.rsk.config.RemascConfig; 23 import co.rsk.config.RemascConfigFactory; 24 import co.rsk.config.RskSystemProperties; 25 import co.rsk.core.RskAddress; 26 import co.rsk.pcc.altBN128.BN128Addition; 27 import co.rsk.pcc.altBN128.BN128Multiplication; 28 import co.rsk.pcc.altBN128.BN128Pairing; 29 import co.rsk.pcc.altBN128.impls.AbstractAltBN128; 30 import co.rsk.pcc.blockheader.BlockHeaderContract; 31 import co.rsk.pcc.bto.HDWalletUtils; 32 import co.rsk.peg.Bridge; 33 import co.rsk.peg.BridgeSupportFactory; 34 import co.rsk.remasc.RemascContract; 35 import co.rsk.rpc.modules.trace.ProgramSubtrace; 36 import org.ethereum.config.blockchain.upgrades.ActivationConfig; 37 import org.ethereum.config.blockchain.upgrades.ConsensusRule; 38 import org.ethereum.core.Block; 39 import org.ethereum.core.Repository; 40 import org.ethereum.core.Transaction; 41 import org.ethereum.crypto.ECKey; 42 import org.ethereum.crypto.HashUtil; 43 import org.ethereum.crypto.signature.ECDSASignature; 44 import org.ethereum.crypto.signature.Secp256k1; 45 import org.ethereum.crypto.cryptohash.Blake2b; 46 import org.ethereum.db.BlockStore; 47 import org.ethereum.db.ReceiptStore; 48 import org.ethereum.util.BIUtil; 49 import org.ethereum.util.ByteUtil; 50 import org.ethereum.vm.exception.VMException; 51  52 import java.math.BigInteger; 53 import java.nio.ByteBuffer; 54 import java.nio.ByteOrder; 55 import java.util.*; 56 import java.util.stream.Collectors; 57 import java.util.stream.Stream; 58  59 import static org.ethereum.util.ByteUtil.*; 60  61  62  63 /** 64  * @author Roman Mandeleil 65  * @since 09.01.2015 66  */ 67 public class PrecompiledContracts { 68  69  public static final String ECRECOVER_ADDR_STR = "0000000000000000000000000000000000000001"; 70  public static final String SHA256_ADDR_STR = "0000000000000000000000000000000000000002"; 71  public static final String RIPEMPD160_ADDR_STR = "0000000000000000000000000000000000000003"; 72  public static final String IDENTITY_ADDR_STR = "0000000000000000000000000000000000000004"; 73  public static final String BIG_INT_MODEXP_ADDR_STR = "0000000000000000000000000000000000000005"; 74  public static final String ALT_BN_128_ADD_ADDR_STR = "0000000000000000000000000000000000000006"; 75  public static final String ALT_BN_128_MUL_ADDR_STR = "0000000000000000000000000000000000000007"; 76  public static final String ALT_BN_128_PAIRING_ADDR_STR = "0000000000000000000000000000000000000008"; 77  public static final String BLAKE2F_ADDR_STR = "0000000000000000000000000000000000000009"; 78  public static final String BRIDGE_ADDR_STR = "0000000000000000000000000000000001000006"; 79  public static final String REMASC_ADDR_STR = "0000000000000000000000000000000001000008"; 80  public static final String HD_WALLET_UTILS_ADDR_STR = "0000000000000000000000000000000001000009"; 81  public static final String BLOCK_HEADER_ADDR_STR = "0000000000000000000000000000000001000010"; 82  83  public static final DataWord ECRECOVER_ADDR_DW = DataWord.valueFromHex(ECRECOVER_ADDR_STR); 84  public static final DataWord SHA256_ADDR_DW = DataWord.valueFromHex(SHA256_ADDR_STR); 85  public static final DataWord RIPEMPD160_ADDR_DW = DataWord.valueFromHex(RIPEMPD160_ADDR_STR); 86  public static final DataWord IDENTITY_ADDR_DW = DataWord.valueFromHex(IDENTITY_ADDR_STR); 87  public static final DataWord BIG_INT_MODEXP_ADDR_DW = DataWord.valueFromHex(BIG_INT_MODEXP_ADDR_STR); 88  public static final DataWord ALT_BN_128_ADD_DW = DataWord.valueFromHex(ALT_BN_128_ADD_ADDR_STR); 89  public static final DataWord ALT_BN_128_MUL_DW = DataWord.valueFromHex(ALT_BN_128_MUL_ADDR_STR); 90  public static final DataWord ALT_BN_128_PAIRING_DW = DataWord.valueFromHex(ALT_BN_128_PAIRING_ADDR_STR); 91  public static final DataWord BLAKE2F_ADDR_DW = DataWord.valueFromHex(BLAKE2F_ADDR_STR); 92  public static final DataWord BRIDGE_ADDR_DW = DataWord.valueFromHex(BRIDGE_ADDR_STR); 93  public static final DataWord REMASC_ADDR_DW = DataWord.valueFromHex(REMASC_ADDR_STR); 94  public static final DataWord HD_WALLET_UTILS_ADDR_DW = DataWord.valueFromHex(HD_WALLET_UTILS_ADDR_STR); 95  public static final DataWord BLOCK_HEADER_ADDR_DW = DataWord.valueFromHex(BLOCK_HEADER_ADDR_STR); 96  97  public static final RskAddress ECRECOVER_ADDR = new RskAddress(ECRECOVER_ADDR_DW); 98  public static final RskAddress SHA256_ADDR = new RskAddress(SHA256_ADDR_DW); 99  public static final RskAddress RIPEMPD160_ADDR = new RskAddress(RIPEMPD160_ADDR_DW); 100  public static final RskAddress IDENTITY_ADDR = new RskAddress(IDENTITY_ADDR_DW); 101  public static final RskAddress BIG_INT_MODEXP_ADDR = new RskAddress(BIG_INT_MODEXP_ADDR_DW); 102  public static final RskAddress ALT_BN_128_ADD_ADDR = new RskAddress(ALT_BN_128_ADD_DW); 103  public static final RskAddress ALT_BN_128_MUL_ADDR = new RskAddress(ALT_BN_128_MUL_DW); 104  public static final RskAddress ALT_BN_128_PAIRING_ADDR = new RskAddress(ALT_BN_128_PAIRING_DW); 105  public static final RskAddress BLAKE2F_ADDR = new RskAddress(BLAKE2F_ADDR_DW); 106  public static final RskAddress BRIDGE_ADDR = new RskAddress(BRIDGE_ADDR_DW); 107  public static final RskAddress REMASC_ADDR = new RskAddress(REMASC_ADDR_DW); 108  public static final RskAddress HD_WALLET_UTILS_ADDR = new RskAddress(HD_WALLET_UTILS_ADDR_STR); 109  public static final RskAddress BLOCK_HEADER_ADDR = new RskAddress(BLOCK_HEADER_ADDR_STR); 110  111  public static final List<RskAddress> GENESIS_ADDRESSES = Collections.unmodifiableList(Arrays.asList( 112  ECRECOVER_ADDR, 113  SHA256_ADDR, 114  RIPEMPD160_ADDR, 115  IDENTITY_ADDR, 116  BIG_INT_MODEXP_ADDR, 117  BRIDGE_ADDR, 118  REMASC_ADDR 119  )); 120  121  // this maps needs to be updated by hand any time a new pcc is added 122  public static final Map<RskAddress, ConsensusRule> CONSENSUS_ENABLED_ADDRESSES = Collections.unmodifiableMap( 123  Stream.of( 124  new AbstractMap.SimpleEntry<>(HD_WALLET_UTILS_ADDR, ConsensusRule.RSKIP106), 125  new AbstractMap.SimpleEntry<>(BLOCK_HEADER_ADDR, ConsensusRule.RSKIP119), 126  new AbstractMap.SimpleEntry<>(ALT_BN_128_ADD_ADDR, ConsensusRule.RSKIP137), 127  new AbstractMap.SimpleEntry<>(ALT_BN_128_MUL_ADDR, ConsensusRule.RSKIP137), 128  new AbstractMap.SimpleEntry<>(ALT_BN_128_PAIRING_ADDR, ConsensusRule.RSKIP137), 129  new AbstractMap.SimpleEntry<>(BLAKE2F_ADDR, ConsensusRule.RSKIP153) 130  ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) 131  ); 132  133  private static ECRecover ecRecover = new ECRecover(); 134  private static Sha256 sha256 = new Sha256(); 135  private static Ripempd160 ripempd160 = new Ripempd160(); 136  private static Identity identity = new Identity(); 137  private static BigIntegerModexp bigIntegerModexp = new BigIntegerModexp(); 138  private final RskSystemProperties config; 139  private final BridgeSupportFactory bridgeSupportFactory; 140  141  public PrecompiledContracts(RskSystemProperties config, BridgeSupportFactory bridgeSupportFactory) { 142  this.config = config; 143  this.bridgeSupportFactory = bridgeSupportFactory; 144  } 145  146  147  public PrecompiledContract getContractForAddress(ActivationConfig.ForBlock activations, DataWord address) { 148  149  if (address == null) { 150  return identity; 151  } 152  if (address.equals(ECRECOVER_ADDR_DW)) { 153  return ecRecover; 154  } 155  if (address.equals(SHA256_ADDR_DW)) { 156  return sha256; 157  } 158  if (address.equals(RIPEMPD160_ADDR_DW)) { 159  return ripempd160; 160  } 161  if (address.equals(IDENTITY_ADDR_DW)) { 162  return identity; 163  } 164  if (address.equals(BRIDGE_ADDR_DW)) { 165  return new Bridge(BRIDGE_ADDR, config.getNetworkConstants(), config.getActivationConfig(), 166  bridgeSupportFactory); 167  } 168  if (address.equals(BIG_INT_MODEXP_ADDR_DW)) { 169  return bigIntegerModexp; 170  } 171  if (address.equals(REMASC_ADDR_DW)) { 172  RemascConfig remascConfig = new RemascConfigFactory(RemascContract.REMASC_CONFIG).createRemascConfig(config.netName()); 173  return new RemascContract(REMASC_ADDR, remascConfig, config.getNetworkConstants(), config.getActivationConfig()); 174  } 175  176  // TODO(mc) reuse CONSENSUS_ENABLED_ADDRESSES 177  if (activations.isActive(ConsensusRule.RSKIP119) && address.equals(BLOCK_HEADER_ADDR_DW)) { 178  return new BlockHeaderContract(config.getActivationConfig(), BLOCK_HEADER_ADDR); 179  } 180  181  if (activations.isActive(ConsensusRule.RSKIP106) && address.equals(HD_WALLET_UTILS_ADDR_DW)) { 182  return new HDWalletUtils(config.getActivationConfig(), HD_WALLET_UTILS_ADDR); 183  } 184  185  if (activations.isActive(ConsensusRule.RSKIP137) && address.equals(ALT_BN_128_ADD_DW)) { 186  return new BN128Addition(activations, AbstractAltBN128.init()); 187  } 188  189  if (activations.isActive(ConsensusRule.RSKIP137) && address.equals(ALT_BN_128_MUL_DW)) { 190  return new BN128Multiplication(activations, AbstractAltBN128.init()); 191  } 192  193  if (activations.isActive(ConsensusRule.RSKIP137) && address.equals(ALT_BN_128_PAIRING_DW)) { 194  return new BN128Pairing(activations, AbstractAltBN128.init()); 195  } 196  197  if (activations.isActive(ConsensusRule.RSKIP153) && address.equals(BLAKE2F_ADDR_DW)) { 198  return new Blake2F(); 199  } 200  201  return null; 202  } 203  204  public abstract static class PrecompiledContract { 205  public RskAddress contractAddress; 206  207  public abstract long getGasForData(byte[] data); 208  209  public void init(Transaction tx, Block executionBlock, Repository repository, BlockStore blockStore, ReceiptStore receiptStore, List<LogInfo> logs) {} 210  211  public List<ProgramSubtrace> getSubtraces() { return Collections.emptyList(); } 212  213  public abstract byte[] execute(byte[] data) throws VMException; 214  } 215  216  public static class Identity extends PrecompiledContract { 217  218  public Identity() { 219  } 220  221  @Override 222  public long getGasForData(byte[] data) { 223  224  // gas charge for the execution: 225  // minimum 15 and additional 3 for each 32 bytes word (round up) 226  if (data == null) { 227  return 15; 228  } 229  long variableCost = GasCost.multiply(GasCost.add(data.length, 31) / 32, 3); 230  return GasCost.add(15, variableCost); 231  } 232  233  @Override 234  public byte[] execute(byte[] data) { 235  return data; 236  } 237  } 238  239  public static class Sha256 extends PrecompiledContract { 240  241  242  @Override 243  public long getGasForData(byte[] data) { 244  245  // gas charge for the execution: 246  // minimum 60 and additional 12 for each 32 bytes word (round up) 247  if (data == null) { 248  return 60; 249  } 250  long variableCost = GasCost.multiply(GasCost.add(data.length, 31) / 32, 12); 251  return GasCost.add(60, variableCost); 252  } 253  254  @Override 255  public byte[] execute(byte[] data) { 256  257  if (data == null) { 258  return HashUtil.sha256(ByteUtil.EMPTY_BYTE_ARRAY); 259  } 260  return HashUtil.sha256(data); 261  } 262  } 263  264  265  public static class Ripempd160 extends PrecompiledContract { 266  267  268  @Override 269  public long getGasForData(byte[] data) { 270  271  // TODO Replace magic numbers with constants 272  // gas charge for the execution: 273  // minimum 600 and additional 120 for each 32 bytes word (round up) 274  if (data == null) { 275  return 600; 276  } 277  long variableCost = GasCost.multiply(GasCost.add(data.length, 31) / 32, 120); 278  return GasCost.add(600, variableCost); 279  } 280  281  @Override 282  public byte[] execute(byte[] data) { 283  284  byte[] result = null; 285  if (data == null) { 286  result = HashUtil.ripemd160(ByteUtil.EMPTY_BYTE_ARRAY); 287  } 288  else { 289  result = HashUtil.ripemd160(data); 290  } 291  292  return DataWord.valueOf(result).getData(); 293  } 294  } 295  296  297  public static class ECRecover extends PrecompiledContract { 298  299  @Override 300  public long getGasForData(byte[] data) { 301  return 3000; 302  } 303  304  @Override 305  public byte[] execute(byte[] data) throws VMException { 306  307  byte[] h = new byte[32]; 308  byte[] v = new byte[32]; 309  byte[] r = new byte[32]; 310  byte[] s = new byte[32]; 311  312  DataWord out = null; 313  314  try { 315  System.arraycopy(data, 0, h, 0, 32); 316  System.arraycopy(data, 32, v, 0, 32); 317  System.arraycopy(data, 64, r, 0, 32); 318  319  int sLength = data.length < 128 ? data.length - 96 : 32; 320  System.arraycopy(data, 96, s, 0, sLength); 321  322  if (isValid(r, s, v)) { 323  ECDSASignature signature = ECDSASignature.fromComponents(r, s, v[31]); 324  325  ECKey key = Secp256k1.getInstance().signatureToKey(h, signature); 326  out = DataWord.valueOf(key.getAddress()); 327  } 328  } catch (Exception any) { 329  } 330  331  if (out == null) { 332  return new byte[0]; 333  } else { 334  return out.getData(); 335  } 336  } 337  338  private boolean isValid(byte[] rBytes, byte[] sBytes, byte[] vBytes) { 339  340  byte v = vBytes[vBytes.length - 1]; 341  BigInteger r = new BigInteger(1, rBytes); 342  BigInteger s = new BigInteger(1, sBytes); 343  344  return ECDSASignature.validateComponents(r, s, v); 345  } 346  } 347  348  /** 349  * Computes modular exponentiation on big numbers 350  * 351  * format of data[] array: 352  * [length_of_BASE] [length_of_EXPONENT] [length_of_MODULUS] [BASE] [EXPONENT] [MODULUS] 353  * where every length is a 32-byte left-padded integer representing the number of bytes. 354  * Call data is assumed to be infinitely right-padded with zero bytes. 355  * 356  * Returns an output as a byte array with the same length as the modulus 357  */ 358  public static class BigIntegerModexp extends PrecompiledContract { 359  360  private static final int BASE = 0; 361  private static final int EXPONENT = 1; 362  private static final int MODULUS = 2; 363  364  private static final BigInteger GQUAD_DIVISOR = BigInteger.valueOf(20); 365  366  private static final int ARGS_OFFSET = 32 * 3; // addresses length part 367  368  @Override 369  public long getGasForData(byte[] data) { 370  byte[] safeData = data==null?EMPTY_BYTE_ARRAY:data; 371  372  int baseLen = parseLen(safeData, BASE); 373  int expLen = parseLen(safeData, EXPONENT); 374  int modLen = parseLen(safeData, MODULUS); 375  376  long multComplexity = GasCost.toGas(getMultComplexity(Math.max(baseLen, modLen))); 377  378  byte[] expHighBytes; 379  try { 380  int offset = Math.addExact(ARGS_OFFSET, baseLen); 381  expHighBytes = parseBytes(safeData, offset, Math.min(expLen, 32)); 382  } catch (ArithmeticException e) { 383  expHighBytes = ByteUtil.EMPTY_BYTE_ARRAY; 384  } 385  386  long adjExpLen = getAdjustedExponentLength(expHighBytes, expLen); 387  388  BigInteger gas = BigInteger.valueOf(multComplexity).multiply( 389  BigInteger.valueOf(Math.max(adjExpLen, 1))).divide(GQUAD_DIVISOR); 390  391  return GasCost.toGas(gas); 392  } 393  394  @Override 395  public byte[] execute(byte[] data) { 396  397  if (data == null) { 398  return EMPTY_BYTE_ARRAY; 399  } 400  401  try { 402  int baseLen = parseLen(data, BASE); 403  int expLen = parseLen(data, EXPONENT); 404  int modLen = parseLen(data, MODULUS); 405  406  int expOffset = Math.addExact(ARGS_OFFSET, baseLen); 407  int modOffset = Math.addExact(expOffset, expLen); 408  409  // whenever an offset gets too big we will get BigInteger.ZERO back 410  BigInteger base = parseArg(data, ARGS_OFFSET, baseLen); 411  BigInteger exp = parseArg(data, expOffset, expLen); 412  BigInteger mod = parseArg(data, modOffset, modLen); 413  414  if (mod.equals(BigInteger.ZERO)) { 415  // Modulo 0 is undefined, return zero 416  return ByteUtil.leftPadBytes(ByteUtil.EMPTY_BYTE_ARRAY, modLen); 417  } 418  419  byte[] res = stripLeadingZeroes(base.modPow(exp, mod).toByteArray()); 420  return ByteUtil.leftPadBytes(res, modLen); 421  } catch (ArithmeticException e) { 422  return ByteUtil.EMPTY_BYTE_ARRAY; 423  } 424  } 425  426  private long getMultComplexity(long x) { 427  428  long x2 = x * x; 429  430  if (x <= 64) { 431  return x2; 432  } 433  if (x <= 1024) { 434  return x2 / 4 + 96 * x - 3072; 435  } 436  437  return x2 / 16 + 480 * x - 199680; 438  } 439  440  private long getAdjustedExponentLength(byte[] expHighBytes, long expLen) { 441  442  int leadingZeros = numberOfLeadingZeros(expHighBytes); 443  int highestBit = 8 * expHighBytes.length - leadingZeros; 444  445  // set index basement to zero 446  if (highestBit > 0) { 447  highestBit--; 448  } 449  450  if (expLen <= 32) { 451  return highestBit; 452  } else { 453  return 8 * (expLen - 32) + highestBit; 454  } 455  } 456  457  private int parseLen(byte[] data, int idx) { 458  byte[] bytes = parseBytes(data, 32 * idx, 32); 459  return DataWord.valueOf(bytes).intValueSafe(); 460  } 461  462  private BigInteger parseArg(byte[] data, int offset, int len) { 463  byte[] bytes = parseBytes(data, offset, len); 464  return BIUtil.toBI(bytes); 465  } 466  467  } 468  469  470  public static class Blake2F extends PrecompiledContract { 471  472  private static final int BLAKE2F_INPUT_LEN = 213; 473  private static final byte BLAKE2F_FINAL_BLOCK_BYTES = 1; 474  private static final byte BLAKE2F_NON_FINAL_BLOCK_BYTES = 0; 475  476  public static final String BLAKE2F_ERROR_INPUT_LENGHT = "input length for BLAKE2 F precompile should be exactly 213 bytes"; 477  public static final String BLAKE2F_ERROR_FINAL_BLOCK_BYTES = "incorrect final block indicator flag"; 478  479  @Override 480  public long getGasForData(byte[] data) { 481  if (data.length != BLAKE2F_INPUT_LEN) { 482  // Input is malformed, we can't read the number of rounds. 483  // Precompile can't be executed so we set its price to 0. 484  return 0; 485  } 486  487  ByteBuffer bb = ByteBuffer.wrap(data); 488  bb.order(ByteOrder.BIG_ENDIAN); 489  return bb.getInt() & 0x00000000ffffffffL; 490  } 491  492  @Override 493  public byte[] execute(byte[] data) throws VMException { 494  if (data.length != BLAKE2F_INPUT_LEN) { 495  throw new VMException(BLAKE2F_ERROR_INPUT_LENGHT); 496  } 497  if (data[212] != BLAKE2F_NON_FINAL_BLOCK_BYTES && data[212] != BLAKE2F_FINAL_BLOCK_BYTES) { 498  throw new VMException(BLAKE2F_ERROR_FINAL_BLOCK_BYTES); 499  } 500  501  ByteBuffer bb = ByteBuffer.wrap(data); 502  bb.order(ByteOrder.BIG_ENDIAN); 503  long rounds = bb.getInt() & 0x00000000ffffffffL; 504  505  long[] h = new long[8]; 506  bb.order(ByteOrder.LITTLE_ENDIAN); 507  for (int i = 0; i < 8; i++) { 508  h[i] = bb.getLong(); 509  } 510  511  long[] m = new long[16]; 512  for (int i = 0; i < 16; i++) { 513  m[i] = bb.getLong(); 514  } 515  516  long[] t = new long[2]; 517  t[0] = bb.getLong(); 518  t[1] = bb.getLong(); 519  520  boolean f = (data[212] == BLAKE2F_FINAL_BLOCK_BYTES); 521  522  Blake2b.functionF(h, m, t, f, rounds); 523  ByteBuffer output = ByteBuffer.allocate(64); 524  output.order(ByteOrder.LITTLE_ENDIAN); 525  for (int i = 0; i < 8; i++) { 526  output.putLong(h[i]); 527  } 528  return output.array(); 529  } 530  } 531  532 }