Fix EXP to use modPow for performance and mod all calculations to (2^256)-1
This commit is contained in:
parent
5905566a1f
commit
bbaef7e3c7
|
@ -182,8 +182,8 @@ public class TestRunner {
|
|||
String output =
|
||||
String.format("Storage value different: key [ %s ], expectedValue: [ %s ], actualValue: [ %s ]",
|
||||
Hex.toHexString(storageKey.getData()),
|
||||
Hex.toHexString(actualValue.getData()),
|
||||
Hex.toHexString(expectedStValue)
|
||||
Hex.toHexString(expectedStValue),
|
||||
Hex.toHexString(actualValue.getData())
|
||||
);
|
||||
logger.info(output);
|
||||
results.add(output);
|
||||
|
@ -228,7 +228,7 @@ public class TestRunner {
|
|||
if (!assertDestination) {
|
||||
|
||||
String output =
|
||||
String.format("Call/Create destination is different expected: [ %s ], result: [ %s ]",
|
||||
String.format("Call/Create destination is different. Expected: [ %s ], result: [ %s ]",
|
||||
Hex.toHexString(expectedCallCreate.getDestination()),
|
||||
Hex.toHexString(resultCallCreate.getDestination()));
|
||||
logger.info(output);
|
||||
|
@ -241,7 +241,7 @@ public class TestRunner {
|
|||
if (!assertData) {
|
||||
|
||||
String output =
|
||||
String.format("Call/Create data is different expected: [ %s ], result: [ %s ]",
|
||||
String.format("Call/Create data is different. Expected: [ %s ], result: [ %s ]",
|
||||
Hex.toHexString(expectedCallCreate.getData()),
|
||||
Hex.toHexString(resultCallCreate.getData()));
|
||||
logger.info(output);
|
||||
|
@ -253,7 +253,7 @@ public class TestRunner {
|
|||
resultCallCreate.getGasLimit());
|
||||
if (!assertGasLimit) {
|
||||
String output =
|
||||
String.format("Call/Create gasLimit is different expected: [ %s ], result: [ %s ]",
|
||||
String.format("Call/Create gasLimit is different. Expected: [ %s ], result: [ %s ]",
|
||||
Hex.toHexString(expectedCallCreate.getGasLimit()),
|
||||
Hex.toHexString(resultCallCreate.getGasLimit()));
|
||||
logger.info(output);
|
||||
|
@ -265,7 +265,7 @@ public class TestRunner {
|
|||
resultCallCreate.getValue());
|
||||
if (!assertValue) {
|
||||
String output =
|
||||
String.format("Call/Create value is different expected: [ %s ], result: [ %s ]",
|
||||
String.format("Call/Create value is different. Expected: [ %s ], result: [ %s ]",
|
||||
Hex.toHexString(expectedCallCreate.getValue()),
|
||||
Hex.toHexString(resultCallCreate.getValue()));
|
||||
logger.info(output);
|
||||
|
@ -283,7 +283,7 @@ public class TestRunner {
|
|||
if (!Arrays.equals(expectedHReturn, actualHReturn)) {
|
||||
|
||||
String output =
|
||||
String.format("HReturn is different expected hReturn: [ %s ], actual hReturn: [ %s ]",
|
||||
String.format("HReturn is different. Expected hReturn: [ %s ], actual hReturn: [ %s ]",
|
||||
Hex.toHexString(expectedHReturn),
|
||||
Hex.toHexString(actualHReturn));
|
||||
logger.info(output);
|
||||
|
@ -297,7 +297,7 @@ public class TestRunner {
|
|||
if (!expectedGas.equals(actualGas)) {
|
||||
|
||||
String output =
|
||||
String.format("Gas usage is differnt expected gas usage: [ %s ], actual gas usage: [ %s ]",
|
||||
String.format("Gas usage is different. Expected gas usage: [ %s ], actual gas usage: [ %s ]",
|
||||
expectedGas.toString() ,
|
||||
actualGas.toString());
|
||||
logger.info(output);
|
||||
|
|
|
@ -297,26 +297,10 @@ public class ByteUtil {
|
|||
* @param size
|
||||
* @return Byte array of given size with a copy of the </code>src</code>
|
||||
*/
|
||||
public static byte[] copyToArray(byte[] src, int size) {
|
||||
byte[] dest = ByteBuffer.allocate(size).array();
|
||||
return copyToArray(src, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to copy a byte array into a given byte array.
|
||||
* If the src length is smaller than the given size, the result will be left-padded
|
||||
* with the original bytes.
|
||||
*
|
||||
* @param src
|
||||
* @param dest
|
||||
* @param size
|
||||
* @return Destination byte array filled with a copy of the </code>src</code>
|
||||
*/
|
||||
public static byte[] copyToArray(byte[] src, byte[] dest) {
|
||||
if (src.length > dest.length)
|
||||
System.arraycopy(src, src.length-dest.length, dest, 0, dest.length-1);
|
||||
else
|
||||
System.arraycopy(src, 0, dest, dest.length - src.length, src.length);
|
||||
public static byte[] copyToArray(BigInteger result) {
|
||||
byte[] src = ByteUtil.bigIntegerToBytes(result);
|
||||
byte[] dest = ByteBuffer.allocate(32).array();
|
||||
System.arraycopy(src, 0, dest, dest.length - src.length, src.length);
|
||||
return dest;
|
||||
}
|
||||
}
|
|
@ -19,6 +19,9 @@ import java.nio.ByteBuffer;
|
|||
*/
|
||||
public class DataWord implements Comparable<DataWord> {
|
||||
|
||||
/* Maximum value of the DataWord */
|
||||
public static final BigInteger _2_256 = BigInteger.valueOf(2).pow(256);
|
||||
public static final BigInteger MAX_VALUE = _2_256.subtract(BigInteger.ONE);
|
||||
public static final DataWord ZERO = new DataWord(new byte[32]); // don't push it in to the stack
|
||||
public static final DataWord ZERO_EMPTY_ARRAY = new DataWord(new byte[0]); // don't push it in to the stack
|
||||
|
||||
|
@ -164,7 +167,7 @@ public class DataWord implements Comparable<DataWord> {
|
|||
// old add-method with BigInteger quick hack
|
||||
public void add2(DataWord word) {
|
||||
BigInteger result = value().add(word.value());
|
||||
this.data = ByteUtil.copyToArray(result.toByteArray(), 32);
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
}
|
||||
|
||||
// TODO: mul can be done in more efficient way
|
||||
|
@ -172,7 +175,7 @@ public class DataWord implements Comparable<DataWord> {
|
|||
// TODO without BigInteger quick hack
|
||||
public void mul(DataWord word) {
|
||||
BigInteger result = value().multiply(word.value());
|
||||
this.data = ByteUtil.copyToArray(result.toByteArray(), 32);
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
}
|
||||
|
||||
// TODO: improve with no BigInteger
|
||||
|
@ -184,7 +187,7 @@ public class DataWord implements Comparable<DataWord> {
|
|||
}
|
||||
|
||||
BigInteger result = value().divide(word.value());
|
||||
this.data = ByteUtil.copyToArray(result.toByteArray(), 32);
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
}
|
||||
|
||||
// TODO: improve with no BigInteger
|
||||
|
@ -196,25 +199,20 @@ public class DataWord implements Comparable<DataWord> {
|
|||
}
|
||||
|
||||
BigInteger result = sValue().divide(word.sValue());
|
||||
|
||||
ByteBuffer data = ByteBuffer.allocate(32);
|
||||
if (result.signum() == -1)
|
||||
Arrays.fill(data.array(), (byte) 0xFF);
|
||||
|
||||
this.data = ByteUtil.copyToArray(result.toByteArray(), data.array());
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
}
|
||||
|
||||
|
||||
// TODO: improve with no BigInteger
|
||||
public void sub(DataWord word) {
|
||||
BigInteger result = value().subtract(word.value());
|
||||
this.data = ByteUtil.copyToArray(result.toByteArray(), 32);
|
||||
BigInteger result = value().subtract(word.value());
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
}
|
||||
|
||||
// TODO: improve with no BigInteger
|
||||
public void exp(DataWord word) {
|
||||
BigInteger result = value().pow(word.intValue());
|
||||
this.data = ByteUtil.copyToArray(result.toByteArray(), 32);
|
||||
BigInteger result = value().modPow(word.value(), _2_256);
|
||||
this.data = ByteUtil.copyToArray(result);
|
||||
}
|
||||
|
||||
// TODO: improve with no BigInteger
|
||||
|
@ -226,7 +224,7 @@ public class DataWord implements Comparable<DataWord> {
|
|||
}
|
||||
|
||||
BigInteger result = value().mod(word.value());
|
||||
this.data = ByteUtil.copyToArray(result.toByteArray(), 32);
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
}
|
||||
|
||||
// TODO: improve with no BigInteger
|
||||
|
@ -238,12 +236,7 @@ public class DataWord implements Comparable<DataWord> {
|
|||
}
|
||||
|
||||
BigInteger result = sValue().mod(word.sValue());
|
||||
|
||||
ByteBuffer data = ByteBuffer.allocate(32);
|
||||
if (result.signum() == -1)
|
||||
Arrays.fill(data.array(), (byte) 0xFF);
|
||||
|
||||
this.data = ByteUtil.copyToArray(result.toByteArray(), data.array());
|
||||
this.data = ByteUtil.copyToArray(result.and(MAX_VALUE));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
|
|
@ -2,6 +2,8 @@ package org.ethereum.vm;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
|
@ -120,5 +122,38 @@ public class DataWordTest {
|
|||
assertEquals("0100000000000000000000000000000000000000000000000000000000000000", Hex.toHexString(y.getData()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPow() {
|
||||
|
||||
BigInteger x = BigInteger.valueOf(Integer.MAX_VALUE);
|
||||
BigInteger y = BigInteger.valueOf(1000);
|
||||
|
||||
BigInteger result1 = x.modPow(x, y);
|
||||
BigInteger result2 = pow(x, y);
|
||||
System.out.println(result1);
|
||||
System.out.println(result2);
|
||||
}
|
||||
|
||||
|
||||
public static BigInteger pow(BigInteger x, BigInteger y) {
|
||||
if (y.compareTo(BigInteger.ZERO) < 0)
|
||||
throw new IllegalArgumentException();
|
||||
BigInteger z = x; // z will successively become x^2, x^4, x^8, x^16,
|
||||
// x^32...
|
||||
BigInteger result = BigInteger.ONE;
|
||||
byte[] bytes = y.toByteArray();
|
||||
for (int i = bytes.length - 1; i >= 0; i--) {
|
||||
byte bits = bytes[i];
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if ((bits & 1) != 0)
|
||||
result = result.multiply(z);
|
||||
// short cut out if there are no more bits to handle:
|
||||
if ((bits >>= 1) == 0 && i == 0)
|
||||
return result;
|
||||
z = z.multiply(z);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue