Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4c96817
ENH: represent UInt256 as big-endian limbs
thomas-quadratic Nov 28, 2025
1d36468
FIX: array indices bugs for fromBytesBE and mulMod.
thomas-quadratic Nov 29, 2025
e717b09
FIX: offset indices in mulMod and fromBytesBE
thomas-quadratic Dec 7, 2025
097773d
FIX: spotless
thomas-quadratic Dec 7, 2025
d0033c3
ENH: cleaning addition and compareLimbs
thomas-quadratic Jan 9, 2026
d349e24
ENH: big-endian long limbs for UInt256
thomas-quadratic Jan 12, 2026
772c0ed
ENH: migrated mod to record based UInt256
thomas-quadratic Jan 20, 2026
f544979
FIX: uint256 mod bugs
thomas-quadratic Jan 22, 2026
ddcbf5f
ENH: improve on worst case fromBytesBE
thomas-quadratic Jan 23, 2026
785d721
FIX: spotless
thomas-quadratic Jan 23, 2026
e0f7ff0
REF: records for addMod and mulMod
thomas-quadratic Jan 26, 2026
9a8366d
FIX: spotless and mod bugs
thomas-quadratic Jan 27, 2026
b796ca8
FIX: tests passing
thomas-quadratic Jan 28, 2026
508c600
FIX: spotless
thomas-quadratic Jan 28, 2026
2a03207
ENH: use div2by1 instead of div3by2
thomas-quadratic Jan 29, 2026
80a5768
FIX: spotless
thomas-quadratic Jan 29, 2026
d96c9ac
FIX: javadoc
thomas-quadratic Jan 30, 2026
0c7a1ed
Add record-based UInt256 invariants
moodmosaic Jan 30, 2026
cc137b5
Constrain UInt256 shift invariants to documented precondition
moodmosaic Jan 30, 2026
f2fdbbc
FIX: first reduction step overflow fix + add/sub/mul ops
thomas-quadratic Feb 13, 2026
294795f
ADD: prop tests for add/sub/mul and refactor prop tests
thomas-quadratic Feb 13, 2026
76f716c
Expose bug
siladu Feb 12, 2026
bba0e64
UInt256 with better code layout and perf optimizations
lu-pinto Feb 17, 2026
f2cf0cc
Branchless code for multiplication
lu-pinto Feb 18, 2026
12a4ae6
spotless
lu-pinto Feb 18, 2026
42af362
add branchless code in div2by1 and mod2by1
lu-pinto Feb 18, 2026
9b0806f
Make adc(UInt256) branchless
lu-pinto Feb 20, 2026
328bd3e
Make mac* methods carry branchless
lu-pinto Feb 20, 2026
b3df0fc
Make mul64 method carry branchless
lu-pinto Feb 20, 2026
9cfc476
Make reciprocal, div2by and mod2by1 method branchless
lu-pinto Feb 20, 2026
a9a39e5
Make mulSub* and addBack methods branchless
lu-pinto Feb 20, 2026
3197d9b
Implement fast/slow paths for reduceNormalised methods
lu-pinto Feb 23, 2026
4a28898
Fix issue in mulSubOverflow
lu-pinto Feb 24, 2026
c0dc03f
Fix issue with mulSub borrows
lu-pinto Feb 24, 2026
7e69743
FIX: removed test for code that became dead and fixed spotless
thomas-quadratic Feb 24, 2026
feb732a
Merge branch 'main' into feat/uint256-as-record
lu-pinto Mar 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,942 changes: 1,473 additions & 469 deletions evm/src/main/java/org/hyperledger/besu/evm/UInt256.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,10 @@ public static OperationResult staticOperation(final MessageFrame frame) {
final Bytes value1 = frame.popStackItem();
final Bytes value2 = frame.popStackItem();

if (value2.isZero()) {
resultBytes = Bytes.EMPTY;
} else {
UInt256 b0 = UInt256.fromBytesBE(value0.toArrayUnsafe());
UInt256 b1 = UInt256.fromBytesBE(value1.toArrayUnsafe());
UInt256 b2 = UInt256.fromBytesBE(value2.toArrayUnsafe());
resultBytes = Bytes.wrap(b0.addMod(b1, b2).toBytesBE());
}
UInt256 b0 = UInt256.fromBytesBE(value0.toArrayUnsafe());
UInt256 b1 = UInt256.fromBytesBE(value1.toArrayUnsafe());
UInt256 b2 = UInt256.fromBytesBE(value2.toArrayUnsafe());
resultBytes = Bytes.wrap(b0.addMod(b1, b2).toBytesBE());

frame.pushStackItem(resultBytes);
return addModSuccess;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,9 @@ public static OperationResult staticOperation(final MessageFrame frame) {
final Bytes value0 = frame.popStackItem();
final Bytes value1 = frame.popStackItem();

UInt256 b0 = UInt256.fromBytesBE(value0.toArrayUnsafe());
UInt256 b1 = UInt256.fromBytesBE(value1.toArrayUnsafe());

UInt256 result = b0.add(b1);
byte[] resultArray = result.toBytesBE();
byte[] b0 = value0.toArrayUnsafe();
byte[] b1 = value1.toArrayUnsafe();
byte[] resultArray = UInt256.add(b0, b1);
frame.pushStackItem(Bytes.wrap(resultArray));

return addSuccess;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.hyperledger.besu.evm.gascalculator.GasCalculator;

import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;

/** The Mod operation. */
public class ModOperationOptimized extends AbstractFixedCostOperation {
Expand Down Expand Up @@ -51,14 +50,11 @@ public Operation.OperationResult executeFixedCostOperation(
public static OperationResult staticOperation(final MessageFrame frame) {
final Bytes value0 = frame.popStackItem();
final Bytes value1 = frame.popStackItem();
Bytes resultBytes;
if (value1.isZero()) {
resultBytes = (Bytes) Bytes32.ZERO;
} else {
UInt256 b0 = UInt256.fromBytesBE(value0.toArrayUnsafe());
UInt256 b1 = UInt256.fromBytesBE(value1.toArrayUnsafe());
resultBytes = Bytes.wrap(b0.mod(b1).toBytesBE());
}

UInt256 b0 = UInt256.fromBytesBE(value0.toArrayUnsafe());
UInt256 b1 = UInt256.fromBytesBE(value1.toArrayUnsafe());
Bytes resultBytes = Bytes.wrap(b0.mod(b1).toBytesBE());

frame.pushStackItem(resultBytes);
return modSuccess;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,10 @@ public static OperationResult staticOperation(final MessageFrame frame) {
final Bytes value1 = frame.popStackItem();
final Bytes value2 = frame.popStackItem();

Bytes resultBytes;
if (value2.isZero()) {
resultBytes = Bytes.EMPTY;
} else {
UInt256 b0 = UInt256.fromBytesBE(value0.toArrayUnsafe());
UInt256 b1 = UInt256.fromBytesBE(value1.toArrayUnsafe());
UInt256 b2 = UInt256.fromBytesBE(value2.toArrayUnsafe());
resultBytes = Bytes.wrap(b0.mulMod(b1, b2).toBytesBE());
}
UInt256 b0 = UInt256.fromBytesBE(value0.toArrayUnsafe());
UInt256 b1 = UInt256.fromBytesBE(value1.toArrayUnsafe());
UInt256 b2 = UInt256.fromBytesBE(value2.toArrayUnsafe());
Bytes resultBytes = Bytes.wrap(b0.mulMod(b1, b2).toBytesBE());

frame.pushStackItem(resultBytes);
return mulModSuccess;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.evm.operation;

import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.UInt256;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;

import org.apache.tuweni.bytes.Bytes;

/** The Mul operation. */
public class MulOperationOptimized extends AbstractFixedCostOperation {

/** The Mul operation success result. */
static final OperationResult mulSuccess = new OperationResult(5, null);

/**
* Instantiates a new Mul operation.
*
* @param gasCalculator the gas calculator
*/
public MulOperation(final GasCalculator gasCalculator) {
super(0x02, "MUL", 2, 1, gasCalculator, gasCalculator.getLowTierGasCost());
}

@Override
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
return staticOperation(frame);
}

/**
* Performs mul operation
*
* @param frame the frame
* @return the operation result
*/
public static OperationResult staticOperation(final MessageFrame frame) {
final Bytes value0 = frame.popStackItem();
final Bytes value1 = frame.popStackItem();

UInt256 u0 = UInt256.fromBytesBE(value0.toArrayUnsafe());
UInt256 u1 = UInt256.fromBytesBE(value1.toArrayUnsafe());
Bytes resultBytes = Bytes.wrap(u0.mul(u1).toBytesBE());

frame.pushStackItem(resultBytes);
return mulModSuccess;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.hyperledger.besu.evm.gascalculator.GasCalculator;

import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;

/** The SMod operation. */
public class SModOperationOptimized extends AbstractFixedCostOperation {
Expand Down Expand Up @@ -52,16 +51,11 @@ public static OperationResult staticOperation(final MessageFrame frame) {
final Bytes value0 = frame.popStackItem();
final Bytes value1 = frame.popStackItem();

Bytes resultBytes;
if (value1.isZero()) {
resultBytes = (Bytes) Bytes32.ZERO;
} else {
UInt256 b0 = UInt256.fromBytesBE(value0.toArrayUnsafe());
UInt256 b1 = UInt256.fromBytesBE(value1.toArrayUnsafe());
resultBytes = Bytes.wrap(b0.signedMod(b1).toBytesBE());
}
frame.pushStackItem(resultBytes);
UInt256 b0 = UInt256.fromBytesBE(value0.toArrayUnsafe());
UInt256 b1 = UInt256.fromBytesBE(value1.toArrayUnsafe());
Bytes resultBytes = Bytes.wrap(b0.signedMod(b1).toBytesBE());

frame.pushStackItem(resultBytes);
return smodSuccess;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright contributors to Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.evm.operation;

import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.UInt256;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;

import org.apache.tuweni.bytes.Bytes;

/** The Sub (Subtract) operation. */
public class SubOperationOptimized extends AbstractFixedCostOperation {

/** The Sub operation success result. */
static final OperationResult subSuccess = new OperationResult(3, null);

/**
* Instantiates a new Sub operation.
*
* @param gasCalculator the gas calculator
*/
public SubOperationOptimized(final GasCalculator gasCalculator) {
super(0x03, "SUB", 2, 1, gasCalculator, gasCalculator.getVeryLowTierGasCost());
}

@Override
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
return staticOperation(frame);
}

/**
* Performs Sub operation.
*
* @param frame the frame
* @return the operation result
*/
public static OperationResult staticOperation(final MessageFrame frame) {
final Bytes value0 = frame.popStackItem();
final Bytes value1 = frame.popStackItem();

byte[] b0 = value0.toArrayUnsafe();
byte[] b1 = value1.toArrayUnsafe();
Bytes resultBytes = Bytes.wrap(UInt256.sub(b0, b1));

frame.pushStackItem(resultBytes);
return subSuccess;
}
}
Loading