Fix EXP to use modPow for performance and mod all calculations to (2^256)-1

This commit is contained in:
nicksavers 2014-10-10 13:03:48 +02:00
parent 5905566a1f
commit bbaef7e3c7
4 changed files with 60 additions and 48 deletions

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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() {

View File

@ -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;
}
}