Alert Source Discuss
🚧 Stagnant Standards Track: Core

EIP-5000: MULDIV 指令

引入一个新的指令,以 512 位精度执行 x * y / z

Authors Harikrishnan Mulackal (@hrkrshnn), Alex Beregszaszi (@axic), Paweł Bylica (@chfast)
Created 2022-03-14
Discussion Link https://ethereum-magicians.org/t/muldiv-instruction/9930

摘要

引入一条新指令 MULDIV(x, y, z),以 512 位精度执行 ((x * y) / z) % 2**256z = 0(x * y) / 2**256 的特殊情况。

动机

高级语言中的定点运算在以太坊上非常常见,尤其是在金融应用领域。

虽然定点加法和减法分别只需 addsub 即可完成,但能够有效地进行定点乘法和除法是一项非常受欢迎的功能。一种常用的解决方法是依赖于基于 mulmod 的、相当复杂的实现(大约需要 50 条指令,不包括堆栈操作)。该指令将其减少到单个操作码。

第二个用例可能是在密码学应用中,其中 muldiv 指令允许全精度 256x256->512 的乘法。mul(x y)(或 muldiv(x, y, 1)) 计算低阶 256 位,而 muldiv(x, y, 0) 计算高阶 256 位。

最后,我们的目标是提供一个可以在已检查未检查的算术用例中有效使用的指令。已检查是指在包括除零和回绕行为在内的条件下中止。

规范

引入一条新指令:MULDIV (0x1e)。

  • 从堆栈中弹出 3 个值,先是 x,然后是 yz
  • 如果 z == 0,则 r = (uint512(x) * y) / 2**256
  • 否则 r = (uint512(x) * y / z) % 2**256,其中中间计算以 512 位精度执行。
  • r 推送到堆栈上。
# operations `*` and `//` are done in 512 bit precision
# 运算 `*` 和 `//` 以 512 位精度完成
def muldiv(x, y, z):
    if z == 0:
        return (x * y) // (2**256)
    else:
        return ((x * y) // z) % (2**256)

该指令的成本为 8 gas(又名 mid),与 addmodmulmod 相同。

原理

特殊的 0 情况

EVM 中的所有算术指令都特别处理除法或模 0:这些指令返回 0。我们决定打破一致性,以便提供一个灵活的操作码,可用于检测回绕行为。

替代选项包括:

  • 返回一个用于回绕的标志
  • 返回两个堆栈项,高阶位和低阶位
  • 在 EVM 中计算高阶 256 位:
/// Returns `hi` such that `x × y = hi × 2**256 + mul(x, y)`
/// 返回 `hi` 使得 `x × y = hi × 2**256 + mul(x, y)`
function hob(uint x, uint y) returns (uint hi) {
    uint uint_max = type(uint).max;
    assembly {
        let lo := mul(x, y)
        let mm := mulmod(x, y, uint_max)
        hi := sub(sub(mm, lo), lt(mm, lo))
    }
}

虽然此功能很巧妙且有用,但调用者必须意识到,与其他 EVM 指令不同,传递 0 将具有截然不同的行为。

参数顺序

参数的顺序与 addmodmulmod 匹配。

向后兼容性

这是一条之前不存在的新指令。

测试用例

PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
MULDIV
---
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
PUSH 0x0000000000000000000000000000000000000000000000000000000000000000
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
MULDIV
---
0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
PUSH 0x0000000000000000000000000000000000000000000000000de0b6b3a7640000
PUSH 0x000000000000000000000000000000000000000000000000016345785d8a0000
PUSH 0x00000000000000000000000000000000000000000000d3c21bcecceda1000000
MULDIV
---
0x00000000000000000000000000000000000000000000152d02c7e14af6800000

安全考虑

待定

版权

版权和相关权利已通过 CC0 放弃。

Citation

Please cite this document as:

Harikrishnan Mulackal (@hrkrshnn), Alex Beregszaszi (@axic), Paweł Bylica (@chfast), "EIP-5000: MULDIV 指令 [DRAFT]," Ethereum Improvement Proposals, no. 5000, March 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5000.