0

Is the ADDMOD that commonly used that we needed to create a specific opcode for it? Why couldn't we simply use the ADD opcode + the MOD opcode together?

The same question is also valid for the MULMOD opcode.

1 Answer 1

2

The ADDMOD and MULMOD opcodes have a specificity talked about in the yellow paper.

All intermediate calculations of this operation are not subject to the 2^256 modulo.

This means that you can do arithmetic above the 2^256 bits limitation as their implementation (opAddmod, opMulmod) actually operates on Big Integers internally and only returns the result. As the modulo value cannot be above 2^256, the result cannot overflow.

Take this example :

function classicAddMod() public view returns (uint256 rvalue) {

    uint256 MAX_INT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;

    assembly {
        rvalue := mod(add(MAX_INT, 1), 10)
    }
}

Where add(MAX_INT, 1) causes an overflow, wrapping the value back to 0. Which modulo 10 is still 0. Now, MAX_INT is actually 115792089237316195423570985008687907853269984665640564039457584007913129639935, that value + 1 modulo 10 should give a result of 6.

The following version with ADDMOD actually computes it right, as it avoids the overflow by never putting the intermediate result of the addition into a 256 bit variable (i.e., the 2^256 modulo) :

function opAddMod() public view returns (uint256 rvalue) {

    uint256 MAX_INT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;

    assembly {
        rvalue := addmod(MAX_INT, 1, 10)
    }
}

This one does return the correct result 6 for the aforementioned reasons. Mulmod has a similar behavior.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.