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 }