Opcode Summary
| Property | Value |
|---|---|
| Opcode | 0x08 |
| Mnemonic | ADDMOD |
| Gas | 8 |
| Stack Input | a, b, N |
| Stack Output | (a + b) % N |
| Behavior | Modular addition using a 512-bit intermediate for the a + b step. The intermediate sum does NOT wrap modulo 2^256 — it is computed with full precision before the modulus is applied. If N == 0, returns 0 (no revert at the EVM level). |
Threat Surface
ADDMOD occupies a unique position among EVM arithmetic opcodes: it is explicitly designed to avoid overflow. The intermediate addition a + b is computed in 512-bit precision, so even MAX_UINT256 + MAX_UINT256 (a 257-bit value) is correctly reduced modulo N without information loss. This makes ADDMOD the safe alternative to the ADD + MOD two-step pattern, where the intermediate ADD would silently wrap before the MOD was applied.
However, ADDMOD introduces its own threat surface:
-
Silent zero on
N == 0: At the raw EVM level,addmod(a, b, 0)returns0with no revert. Solidity >= 0.8.0 inserts a compiler-level check that reverts before the opcode executes, but inline assembly, Yul code, and pre-0.8.0 contracts lack this protection. A zero modulus silently discards the computation and returns a mathematically meaningless result. -
False sense of security: Developers may assume ADDMOD provides general-purpose “safe addition” because it avoids overflow. But ADDMOD returns
(a + b) % N, nota + b. If downstream code expects an unbounded sum, the modular reduction silently truncates the result. This is particularly dangerous when ADDMOD is used outside of intentional modular arithmetic contexts. -
Cryptographic misuse: ADDMOD is a core building block for on-chain elliptic curve arithmetic, finite field math, and big-number libraries. Using the wrong modulus (e.g., confusing the field prime
pwith the group ordernin secp256k1) produces results that appear valid but are cryptographically broken. These bugs are subtle, hard to detect in audits, and can compromise signature verification, zero-knowledge proofs, and key derivation. -
Client-level crash history: The go-ethereum uint256 library (v1.9.16-v1.9.17) panicked on
mulmod(a, b, 0)due to a buffer underflow — the same code path handles both MULMOD and ADDMOD’s modulus-zero case. This demonstrates that even EVM client implementations can get theN == 0edge case wrong, turning a smart contract bug into a network-wide denial of service.
Smart Contract Threats
T1: Modulus-by-Zero Producing Silent Zero (High)
At the EVM opcode level, ADDMOD(a, b, 0) returns 0 regardless of a and b. There is no revert, no exception, no flag. If a contract computes a modulus value dynamically and that value reaches zero through a bug, oracle failure, or manipulated input, every ADDMOD operation using it silently returns 0.
Solidity >= 0.8.0 mitigates this by inserting ISZERO(N) → JUMPI → REVERT before the ADDMOD opcode. This check is enforced even inside unchecked { } blocks. However:
- Inline assembly / Yul:
addmod(a, b, N)in assembly has NO compiler-inserted zero check. IfNis zero, the opcode executes and returns0. - Pre-0.8.0 contracts: No compiler protection.
addmod(a, b, 0)returns0silently. - Cross-contract calls: A contract compiled with 0.8.0+ can call a pre-0.8.0 library that uses raw ADDMOD without checks.
// Vulnerable: assembly bypasses Solidity's zero-modulus check
function unsafeAddMod(uint256 a, uint256 b, uint256 n) internal pure returns (uint256 result) {
assembly {
result := addmod(a, b, n) // If n == 0, silently returns 0
}
}Impact: Financial calculations return 0 instead of correct values. In DeFi, this can mean zero-priced assets, bypassed invariant checks, or drained pools.
T2: Incorrect Assumptions About ADDMOD Semantics (Medium)
Developers sometimes use ADDMOD as a “safe add” thinking it merely prevents overflow, without fully accounting for the modular reduction. Two dangerous misconceptions:
-
“ADDMOD is just overflow-safe ADD”: A developer might write
addmod(a, b, 2**256)expecting it to behave like ADD but with overflow safety. In fact,addmod(a, b, 2**256)does return(a + b) % 2^256(identical to ADD), but2**256cannot be represented as a uint256 on the stack — it would be0after truncation, triggering theN == 0case and returning0. The developer must useaddmod(a, b, type(uint256).max)or similar, which produces(a + b) % (2^256 - 1), subtly different from ADD’s wrapping. -
Confusing ADDMOD with checked addition: ADDMOD does not revert on overflow; it reduces modulo N. If a contract uses ADDMOD where it should use checked ADD (Solidity 0.8.0+ default), overflows are silently absorbed into the modular result rather than reverting. The contract continues executing with a reduced value that may violate business logic invariants.
// Bug: developer wanted overflow-safe addition but got modular reduction
uint256 total = addmod(userDeposit, fee, POOL_SIZE);
// If userDeposit + fee > POOL_SIZE, total is silently reduced
// Developer expected a revert or the true sumT3: Misuse in Cryptographic Implementations (High)
On-chain cryptographic libraries (elliptic curve operations, RSA verification, BLS signatures, ZK proof verifiers) rely heavily on ADDMOD for field arithmetic. The secp256k1 curve used by Ethereum has two critical constants:
- Field prime:
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F - Group order:
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
Confusing p and n in ADDMOD operations produces results that pass superficial tests but break cryptographic security:
- Point addition with wrong modulus: Using
addmod(x1, x2, n)instead ofaddmod(x1, x2, p)when computing elliptic curve point coordinates yields points not on the curve, breaking signature verification. - Scalar arithmetic with wrong modulus: Using
addmod(s1, s2, p)instead ofaddmod(s1, s2, n)when combining scalars produces values outside the valid scalar range, enabling signature forgery.
These bugs are extremely subtle because p and n for secp256k1 are both 256-bit values that differ only in their lower 128 bits, and many test vectors happen to produce correct results with either modulus.
T4: Field Arithmetic Errors in Elliptic Curve Math (High)
Beyond modulus confusion, on-chain elliptic curve libraries face structural risks when using ADDMOD:
-
Non-prime modulus: ADDMOD works with any
N, including composite numbers. Field arithmetic requires a prime modulus to guarantee that every nonzero element has a multiplicative inverse. Using a compositeN(e.g., from a corrupted constant or incorrect parameter passing) breaks the field structure, making division undefined for certain elements and producing silently incorrect curve operations. -
Reduction after multi-step computation: Developers sometimes apply ADDMOD only at the final step of a multi-operation computation, assuming intermediate values stay within range. While ADDMOD’s 512-bit intermediate prevents overflow in a single addition, chained operations like
addmod(addmod(a, b, p), c, p)vs.addmod(a, addmod(b, c, p), p)should be equivalent over a prime field but can differ ifpis accidentally changed between calls or if a non-prime modulus is used. -
Missing reduction in mixed opcode chains: When ADDMOD is mixed with regular ADD, MUL, or SHL in the same computation, developers may forget that the non-ADDMOD operations still wrap modulo 2^256. A sequence like
temp = a + b; result = addmod(temp, c, p)has already lost information ifa + boverflowed in the ADD step.
T5: Gas Optimization Traps in Assembly (Medium)
Gas-optimized code often uses inline assembly with ADDMOD to avoid Solidity’s overhead. This introduces several risks:
- No type safety: Assembly ADDMOD operates on raw 256-bit words. Passing a value from a uint128 variable that has dirty upper bits (a known Solidity/Yul issue with packed storage reads) produces incorrect results.
- No zero-check on modulus: As noted in T1, assembly bypasses the compiler’s
N != 0assertion. - Stack manipulation errors: ADDMOD pops 3 values and pushes 1. In complex assembly blocks with many stack operations, it’s easy to feed the wrong stack slot as the modulus, causing the operation to use an unrelated value as
N.
Protocol-Level Threats
P1: Client-Level Denial of Service via Zero Modulus (High — Historical)
CVE-2020-26242 / GHSA-jm5c-rv3w-w83m: In go-ethereum v1.9.16-v1.9.17, the uint256 library used for MULMOD (and sharing code paths with ADDMOD’s modular reduction) panicked when the modulus was 0. The variable dLen remained 0, causing a buffer underflow that accessed index [-1]. This crash occurred during block processing, meaning a single malicious transaction containing mulmod(a, b, 0) would crash all vulnerable geth nodes, dropping them from the network.
The fix required updating the uint256 library to handle the zero-modulus edge case gracefully (returning 0 as specified by the Yellow Paper). This was deployed in geth v1.9.18.
Relevance to ADDMOD: While the CVE specifically references MULMOD, the zero-modulus code path is shared. Any client implementation that doesn’t handle N == 0 correctly for either ADDMOD or MULMOD faces the same DoS risk. The incident demonstrates that even “returns 0” semantics must be explicitly implemented; an unhandled edge case becomes a network-level vulnerability.
P2: Consensus Divergence Risk in Modular Arithmetic (Low)
ADDMOD requires a 512-bit intermediate representation for the addition step. Different EVM implementations may use different big-integer libraries:
- geth: Uses
holiman/uint256with explicit 512-bit support - Nethermind: Uses .NET’s
BigInteger - Besu: Uses Java’s
BigInteger - reth: Uses Rust’s
ruintcrate
If any implementation incorrectly truncates the intermediate to 256 bits before applying the modulus, it would produce different results from other clients, causing a consensus split. While this has not occurred for ADDMOD specifically, the MULMOD case (which requires a 512-bit intermediate for the product) has received more testing attention, and ADDMOD’s simpler arithmetic makes implementation bugs less likely but not impossible.
P3: No Direct DoS Vector (Low)
ADDMOD costs a fixed 8 gas regardless of operand values. It operates purely on the stack with no memory or storage access. The 512-bit intermediate computation is bounded and fast. ADDMOD cannot be used for gas griefing.
P4: Static Analysis Tool Gaps (Low)
The Manticore symbolic execution framework had a bug where ADDMOD and MULMOD operations incorrectly applied 2^256 modulo to the intermediate result, defeating the purpose of the 512-bit precision. This was fixed in PR #1531. Other analysis tools (Mythril, Echidna, Halmos) may have similar gaps. If a security tool incorrectly models ADDMOD, it will miss vulnerabilities in contracts that depend on ADDMOD’s overflow-free semantics — or flag false positives for non-existent overflow issues.
Edge Cases
| Edge Case | Behavior | Security Implication |
|---|---|---|
addmod(a, b, 0) | Returns 0 | Silent zero; bypasses all downstream checks expecting nonzero results |
addmod(a, b, 1) | Returns 0 | Any integer mod 1 is 0; useful only as a constant-zero generator. If N=1 is reached through a bug, all ADDMOD results become 0 |
addmod(MAX_UINT256, 1, 10) | Returns 6 | Correct: 512-bit intermediate prevents overflow. ADD(MAX_UINT256, 1) would return 0, and 0 % 10 = 0 (wrong) |
addmod(MAX_UINT256, MAX_UINT256, MAX_UINT256) | Returns 0 | Correct: (2^256 - 1 + 2^256 - 1) % (2^256 - 1) = (2 * (2^256 - 1)) % (2^256 - 1) = 0 |
addmod(MAX_UINT256, MAX_UINT256, 2^256 - 1) | Returns 0 | Same as above; the 257-bit intermediate 2^257 - 2 is correctly reduced |
addmod(MAX_UINT256, MAX_UINT256, 7) | Returns 4 | 512-bit intermediate 2^257 - 2 mod 7 = 4. Using ADD then MOD: ADD wraps to MAX_UINT256 - 1, then (MAX_UINT256 - 1) % 7 = 3 (wrong!) |
addmod(0, 0, N) | Returns 0 | Safe; identity case |
addmod(a, 0, N) | Returns a % N | ADDMOD always reduces mod N, even when no addition occurs |
addmod(N-1, 1, N) | Returns 0 | Boundary wrap; N mod N is 0 |
addmod(a, b, 2) | Returns 0 or 1 | Parity check of a + b (the true sum, not the truncated one) |
Real-World Exploits
Exploit 1: go-ethereum MulMod/AddMod Zero-Modulus Panic — Network DoS (September 2020)
CVE: CVE-2020-26242 / GHSA-jm5c-rv3w-w83m
Root cause: The holiman/uint256 library used by go-ethereum did not handle a zero divisor in the modular reduction code path. When MULMOD(a, b, 0) was executed, the variable dLen (length of the divisor) remained 0, causing the code to access array index [-1], triggering a panic.
Details: The vulnerability was discovered when geth nodes crashed during synchronization from genesis on the Ropsten testnet. A transaction on Ropsten contained a mulmod(a, b, 0) operation. The EVM Yellow Paper specifies that this should return 0, but the uint256 library assumed a nonzero divisor and performed an out-of-bounds memory access.
The ADDMOD opcode shares the same modular reduction code path for applying % N after the intermediate computation. While the triggering transaction used MULMOD, any transaction using addmod(a, b, 0) on affected geth versions would have produced the same panic.
Impact: All geth nodes running v1.9.16 or v1.9.17 would crash when processing the block containing the malicious transaction. On mainnet, this would have caused a significant portion of the network to go offline simultaneously, as geth is the dominant client. The vulnerability was patched before mainnet exploitation by updating the uint256 library to v1.1.1, which returns 0 for zero modulus.
ADDMOD’s role: ADDMOD and MULMOD share the modular reduction step where the panic occurred. The vulnerability is a direct consequence of the N == 0 semantics being underspecified at the implementation level.
References:
Exploit 2: Manticore Symbolic Execution — Incorrect ADDMOD/MULMOD Modeling
Root cause: The Trail of Bits Manticore framework applied 2^256 modulo to the intermediate result of ADDMOD and MULMOD, defeating their 512-bit precision guarantee.
Details: Manticore’s EVM implementation computed ADDMOD as (a + b) % 2^256 % N instead of the correct (a + b) % N with 512-bit intermediate. This meant that Manticore would report ADDMOD behaved identically to the ADD + MOD two-opcode sequence, missing the critical difference that ADDMOD is designed to prevent.
For example, addmod(MAX_UINT256, 1, 10) should return 6 (since 2^256 % 10 = 6), but the buggy Manticore model would compute ADD(MAX_UINT256, 1) = 0, then 0 % 10 = 0, reporting 0.
Impact: Any security audit or automated analysis that relied on Manticore to verify ADDMOD/MULMOD behavior would have received incorrect results. Contracts correctly using ADDMOD for overflow-safe modular arithmetic might have been falsely flagged, while contracts incorrectly using ADD + MOD might have been incorrectly reported as safe.
ADDMOD’s role: Directly affected. The bug was in the symbolic model of the ADDMOD opcode itself.
References:
Exploit 3: Vyper ecrecover Memory Corruption — Indirect ADDMOD/Field Arithmetic Risk (July 2023)
CVE: CVE-2023-37902
Root cause: The Vyper compiler’s ecrecover built-in did not clear the output buffer before calling the precompile. If signature verification failed, the buffer retained whatever data was previously written there — potentially an immutable value or storage slot address from prior operations.
Details: While this exploit targets ecrecover rather than ADDMOD directly, it illustrates the broader danger of on-chain cryptographic implementations. The ecrecover precompile internally performs elliptic curve field arithmetic (modular addition and multiplication over the secp256k1 field prime). When the precompile’s output is corrupted, any contract using the returned address for authentication is compromised.
Contracts that implement their own elliptic curve math using ADDMOD (rather than relying on precompiles) face analogous risks: if intermediate field values are corrupted through memory management bugs, stack manipulation errors, or wrong-modulus usage, the resulting cryptographic operation appears to succeed but produces an incorrect result.
ADDMOD’s role: Indirect. The exploit demonstrates that field arithmetic errors (the domain where ADDMOD is most critical) can have catastrophic consequences for authentication and authorization.
References:
Attack Scenarios
Scenario A: Zero Modulus via Oracle Failure
// Assembly-heavy DeFi protocol using ADDMOD for field math
contract VulnerableFieldMath {
uint256 public fieldModulus; // Set by governance or oracle
function setModulus(uint256 _mod) external onlyOwner {
fieldModulus = _mod; // No zero check!
}
function fieldAdd(uint256 a, uint256 b) public view returns (uint256 result) {
assembly {
let n := sload(fieldModulus.slot)
result := addmod(a, b, n) // If fieldModulus == 0, returns 0
}
}
function computeShare(uint256 deposit, uint256 bonus) external view returns (uint256) {
uint256 total = fieldAdd(deposit, bonus); // Returns 0 if modulus is 0
// Downstream: user's share is computed as 0, funds are locked or stolen
return total;
}
}Attack: Governance exploit or oracle manipulation sets fieldModulus to 0. All subsequent fieldAdd calls return 0. Users depositing funds receive zero credit.
Scenario B: ADD + MOD vs ADDMOD Confusion
// Developer uses ADD then MOD, not realizing ADDMOD exists
contract IncorrectModularMath {
uint256 constant FIELD_PRIME = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
function add_mod_WRONG(uint256 a, uint256 b) internal pure returns (uint256) {
// BUG: ADD wraps modulo 2^256 BEFORE the MOD is applied
return (a + b) % FIELD_PRIME;
}
function add_mod_CORRECT(uint256 a, uint256 b) internal pure returns (uint256) {
return addmod(a, b, FIELD_PRIME);
}
// When a + b > 2^256:
// WRONG: (a + b) wraps to small value, then % FIELD_PRIME of that small value
// CORRECT: 512-bit (a + b) then % FIELD_PRIME -- mathematically correct
}Attack: An on-chain signature verifier uses add_mod_WRONG for elliptic curve point addition. An attacker crafts inputs where a + b > 2^256, causing the wrong branch of the curve equation to be satisfied. The verifier accepts an invalid signature.
Scenario C: Wrong Modulus in Elliptic Curve Library
contract BrokenECMath {
// secp256k1 constants -- note how similar p and n are
uint256 constant FIELD_PRIME = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
uint256 constant GROUP_ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
function pointAdd(
uint256 x1, uint256 y1,
uint256 x2, uint256 y2
) internal pure returns (uint256 x3, uint256 y3) {
// BUG: Using GROUP_ORDER instead of FIELD_PRIME for coordinate arithmetic
// Point coordinates live in the field F_p, not the scalar group Z_n
uint256 dx = addmod(x2, FIELD_PRIME - x1, GROUP_ORDER); // WRONG modulus!
uint256 dy = addmod(y2, FIELD_PRIME - y1, GROUP_ORDER); // WRONG modulus!
// This produces points not on the curve, enabling signature forgery
// Correct: use FIELD_PRIME for all coordinate operations
// ...
}
}Attack: The difference between FIELD_PRIME and GROUP_ORDER is small enough that most test vectors pass. An attacker finds inputs where the modulus difference matters, producing a “valid” point that is actually not on the curve, and uses it to forge a signature accepted by the verifier.
Scenario D: ADDMOD Used as “Safe ADD” With Unintended Reduction
contract MisusedAddmod {
uint256 constant LARGE_PRIME = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
function safeAdd(uint256 a, uint256 b) internal pure returns (uint256) {
// Developer thinks: "ADDMOD won't overflow, so this is safe addition"
// Reality: result is reduced mod LARGE_PRIME, silently losing value
return addmod(a, b, LARGE_PRIME);
}
function deposit(uint256 amount) external {
uint256 newBalance = safeAdd(balances[msg.sender], amount);
// If balances[msg.sender] + amount >= LARGE_PRIME, newBalance wraps
// The user's balance is LESS than their actual deposits
balances[msg.sender] = newBalance;
}
}Mitigations
| Threat | Mitigation | Implementation |
|---|---|---|
| T1: Zero modulus | Always validate N != 0 before ADDMOD | Use Solidity >= 0.8.0 (automatic check); in assembly: if iszero(n) { revert(0, 0) } |
| T1: Assembly bypass | Wrap assembly ADDMOD in a Solidity function with validation | require(n != 0); assembly { result := addmod(a, b, n) } |
| T2: Semantic confusion | Use ADDMOD only for intentional modular arithmetic | For overflow-safe addition, use Solidity 0.8.0+ checked arithmetic instead |
| T2: Unintended reduction | Verify a + b < N if reduction is not desired | require(a < N && b < N) or use checked ADD when you need the true sum |
| T3: Wrong modulus | Define cryptographic constants as immutable or constant; review every ADDMOD call for correct modulus | Named constants: uint256 constant SECP256K1_P = 0x...FC2F; uint256 constant SECP256K1_N = 0x...4141; |
| T3: Modulus confusion | Separate field operations from scalar operations into distinct functions | fieldAdd(a, b) always uses p; scalarAdd(a, b) always uses n |
| T4: Non-prime modulus | Validate modulus primality at deploy time for configurable systems | Use well-known constant primes; if modulus is dynamic, add primality checks |
| T4: Mixed opcode chains | Use ADDMOD for ALL additions in modular arithmetic sequences | Never mix ADD and ADDMOD in the same field computation |
| T5: Dirty bits in assembly | Mask inputs to 256 bits before ADDMOD in assembly | a := and(a, MAX_UINT256) (usually unnecessary but defensive) |
| General | Use precompiles for standard curves | Use ecrecover (secp256k1) or EIP-196/197 precompiles (alt_bn128) instead of hand-rolled ADDMOD-based curve math |
| General | Static analysis | Slither custom detectors for ADDMOD with non-constant modulus; formal verification with Halmos or Certora |
Compiler/EIP-Based Protections
- Solidity 0.8.0+ (2020): Automatic revert when ADDMOD’s modulus is zero. The compiler emits
ISZERO(N) → JUMPI → REVERTbefore the ADDMOD opcode. This check persists even insideunchecked { }blocks — the only way to bypass it is inline assembly. - SMTChecker: Solidity’s built-in formal verification engine (added in PR #9910) includes verification targets for ADDMOD and MULMOD, checking that the modulus is nonzero.
- EIP-196/197 Precompiles: For alt_bn128 elliptic curve operations, precompiled contracts at addresses
0x06,0x07, and0x08perform field arithmetic correctly at the client level, avoiding the need for hand-rolled ADDMOD-based curve math. - EIP-6690 (EVMMAX, Stagnant): Proposes extended modular arithmetic opcodes supporting moduli up to 2^768, with explicit modulus setup and validation. If adopted, would replace many current ADDMOD/MULMOD patterns with safer, purpose-built instructions.
Severity Summary
| Threat ID | Category | Severity | Likelihood | Real-World Precedent |
|---|---|---|---|---|
| T1 | Smart Contract | High | Medium (assembly) / Low (Solidity 0.8+) | go-ethereum CVE-2020-26242 (network DoS from zero modulus) |
| T2 | Smart Contract | Medium | Medium | No specific exploit; common audit finding in DeFi math libraries |
| T3 | Smart Contract | High | Low | Vyper ecrecover CVE-2023-37902 (analogous field arithmetic corruption) |
| T4 | Smart Contract | High | Low | Manticore PR #1531 (incorrect modeling); theoretical for deployed contracts |
| T5 | Smart Contract | Medium | Low | Solidity dirty-bits issues in packed storage reads |
| P1 | Protocol | High (Historical) | Patched | CVE-2020-26242: geth panic on zero modulus |
| P2 | Protocol | Low | Very Low | No known divergence; theoretical risk in new client implementations |
| P3 | Protocol | Low | N/A | — |
| P4 | Protocol | Low | Low | Manticore ADDMOD modeling bug |
Related Opcodes
| Opcode | Relationship |
|---|---|
| MULMOD (0x09) | Sister opcode; modular multiplication with 512-bit intermediate product. Same N == 0 → 0 behavior. Shares the zero-modulus code path that caused CVE-2020-26242 |
| ADD (0x01) | Standard addition; wraps modulo 2^256. ADDMOD exists specifically to avoid ADD’s overflow in modular arithmetic contexts. ADD + MOD is NOT equivalent to ADDMOD when a + b >= 2^256 |
| MOD (0x06) | Standard unsigned modulus. MOD(ADD(a, b), N) gives wrong results when a + b overflows; ADDMOD(a, b, N) does not |
| DIV (0x04) | Division; returns 0 for DIV(a, 0). Same silent-zero-on-zero-divisor pattern as ADDMOD |
| EXP (0x0A) | Exponentiation wraps modulo 2^256. No EXPMOD opcode exists in the EVM; modular exponentiation requires the precompile at address 0x05 |
| MUL (0x02) | Standard multiplication; wraps modulo 2^256. MULMOD is MUL’s overflow-safe counterpart, just as ADDMOD is ADD’s |