Evm
為什麼要使用專用的 ADDMOD 操作碼?
常用的 ADDMOD 是不是我們需要為其創建特定的操作碼?為什麼我們不能簡單地同時使用 ADD 操作碼 + MOD 操作碼?
同樣的問題也適用於 MULMOD 操作碼。
ADDMOD 和 MULMOD 操作碼在黃皮書中有一個特殊性。
此操作的所有中間計算都不受 2^256 模數的限制。
這意味著您可以在 2^256 位限制之上進行算術運算,因為它們的實現(opAddmod,opMulmod)實際上在內部對 Big Integers 進行操作,並且只返回結果。由於模值不能高於 2^256,因此結果不會溢出。
舉個例子:
function classicAddMod() public view returns (uint256 rvalue) { uint256 MAX_INT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; assembly { rvalue := mod(add(MAX_INT, 1), 10) } }
Where
add(MAX_INT, 1)
導致溢出,將值包裝回 0。模 10 仍為 0。現在,MAX_INT 實際上是 11579208923731619542357098500868790785326998466564056403945758400791312963993 5,該值 + 1 模 1 的結果應該是 1以下帶有 ADDMOD 的版本實際上計算正確,因為它通過從不將加法的中間結果放入 256 位變數(即2^256 模)來避免溢出:
function opAddMod() public view returns (uint256 rvalue) { uint256 MAX_INT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; assembly { rvalue := addmod(MAX_INT, 1, 10) } }
6
由於上述原因,這確實返回了正確的結果。Mulmod 也有類似的行為。