4_AVM规范

本文档以非正式的方式描述了Arbitrum VM架构的规范。相较于在USENIX Security 2018上发布的Arbitrum白皮书,该版本是经过简化的。另外,还将数据结构向以太坊进一步靠拢,以减少EVM to AVM翻译器的需要。

我们还会进一步做一些优化来节省时间和空间,不过会以与本文档所述内容基本等价为前提。

一个值有下列类型:

  • 整形:256位的整数;
  • 码点:代表在可执行代码中某个点的值(实现形式为(operation, nextcodehash))
  • 元组:一个至多8个元素的数组,数量从0连续递增,每个元素包含一个值;
  • Buffer:字节组成的数组,最长为2^64

注意,整形并没有显性声明是有符号或无符号的。在差别很重要的情况下,该规范会声明哪种运算会区分有符号和无符号(而在没差别的场景下,规范也不做区分)。

特殊值None指的是0-元组(包含0个元素的元组)。

元组的元素中可能包含其他元组。由此,一个元组可以代表任意层级的树结构(更精确地说,一个有向无环图,DAG)。

所有的值都是不可变的。因此,元组是不可能直接或间接包含其自身的(证明:若元组A包含元组B,A一定是在B之后创建的)。

由于元组不可变,并形成了一个无环结构,将元组作为较小数组对象的指针,通过引用计数管理元组的生命周期都是可行的。

运算

有两种类型的运算

  • 基础运算 BasicOp: 简单操作码
  • 立即运算 ImmediateOp: 带有值的操作码

执行运算的行为如下:

  • BasicOp: 根据下面的定义的行为执行操作码
  • ImmediateOp: 首先先将包含的值推入栈。再根据下面的定义的行为执行操作码

一个栈代表着一些值的下推栈(可能是空的)。栈支持推入Push和弹出Pop操作,和通常的栈是一样的。在对空栈进行弹出操作时会导致VM进入错误状态。一个栈的表现形式要么是None(空栈),要么是2元元组[topValue, restOfStack],其中restOfStack也是一个栈。

序列化(Marshaling)

序列化一种可逆的从值到字节数组的映射。在VM外,值通常是已序列化的。

反序列化顾名思义就是反向操作,将字节数组变为值。该文档并不详细讨论反序列化操作,只会提一下:对所有的值V,反序列化(序列化(V))=V。 如果字节数组A无法被序列化,则尝试反序列化A也会报错。

整形会被序列化为

  • the byte 0
  • 该值的32位大端序形态

码点会被序列化为

  • byte val of 1
  • 该运算的序列化
  • 32位nexthHash值

BasicOp被序列化为

  • byte val of 0
  • 该操作码的1位形态

ImmediateOp序列化为

  • byte val of 1
  • 该操作码的1位形态
  • 序列化后的值

元组序列化为

  • byte val of (3 + 元组中元素的数量)
  • 每个元素的值序列化后的串接

Buffer序列化为

  • bytes val of 12
  • buffer长度(LENGTH)的32位大端序形态
  • 代表该buffer值的LENGTH bytes

Buffer的长度定义为:使得b = pre || post且post仅包含0的最小前缀的长度。

对值进行哈希

一个整形的哈希,是其32位大端序编码的Keccak-256,再编码为整形大端序的形态。

计算元组的哈希,将byte value (3 + 元素数量) 串接上元组中元素的哈希,再将该结果进行Keccak-256,再编码为整形大端序的形态。

计算包含BasicOp的码点的哈希,将byte value 1与该操作码的1位形态与32位nextHash进行串接,将该结果进行Keccak-256,再编码为整形大端序的形态。

计算包含ImmediateOp的码点的哈希,将byte value 1与该操作码的1位形态与立即值的32位哈希串接,将该结果进行Keccak-256,再编码为整形大端序的形态。

Buffer的哈希,是该buffer的前LENGTH个字节的梅克尔树哈希,以32位块读取(长度以下一个二次幂向上取整)。空buffer的哈希是32个0的Keccak-256。更准确地说,ROUNDED_LENGTH是最小的X使得X <= LENGTH, X >= 32 且存在N使得X = 2**N。32大小的buffer切片的哈希是Hash(buf) = Keccak-256(buf), and Hash(buf) = Keccak-256(Hash(buf[0..size/2]) || Hash(buf[size/2..size])).

VM状态

VM状态不外乎这几种:特殊状态Halted(暂停),特殊状态ErrorStop,或其他扩展状态。

扩展状态包含下列几种:

  • Current Codepoint,当前码点:代表当前运行所处的码点
  • Data Stack,数据栈:该栈是运算的首要工作区
  • Aux Stack,辅助栈:该栈提供了辅助的存储空间
  • Register,寄存器:一种可变的存储单元,可存储单个值
  • Static,静态:一种在VM初始化时就已经确定的不可变值
  • AVMGas Remaining,AVMGas剩余: 记载了在出现报错前可消耗多少AVMGas的一个整形
  • Error Codepoint,错误码点: Error所对应的码点
  • Pending Message,待处理消息: 记录了待处理的收件箱信息(若有的话)的元组

当VM初始化时,位于扩展状态。Data Stack, Aux Stack, Register, AVMGas Remaining, 和 Error Codepoint 会分别初始化为 None, None, None, MaxUint256, 和Codepoint (0, 0)。创建VM的实体提供Current Codepoint和Static的值。

对VM状态进行哈希

若VM是Halted状态,状态哈希是0.

若VM在ErrorStop状态,状态哈希为1.

如果VM处于扩展状态,其状态哈希的计算如下:串接下列内容Instruction Stack的哈希, Data Stack的哈希, Aux Stack的哈希, Register的哈希, Static的哈希, AVMGas Remaining的32位大端序形态, Error Codepoint的哈希, 待处理消息的哈希,然后对其进行Keccak-256。

运行时环境

运行时环境是VM对外的接口。特定的指令会与运行时进行交互。

运行时环境的实现在不同场景下差别较大。在独立AVM虚拟机情况下,运行时可能由命令行参数或者配置文件控制。在Arbitrum的生产环境下,运行时会由Arbitrum验证者提供,并且会在Arbitrum协议中的断言中的前提条件部分中申明。

运行时环境会为下列事物提供值:

  • 一系列代表着该VM收件箱的信息值

开发者可以假设,运行时环境会满足『时间一致性』属性:如果之前消息的时间戳为T,下一个消息的时间戳会大于等于T。

收件箱与信息

每个VM都有一个收件箱,该收件箱由运行时环境提供。该收件箱包含一系列由一组收件箱指令(下述)的顺序调用返回的值组成,收件箱指令会移除队列中的第一条信息并将其推入Data Stack。

每个在收件箱序列中的值都必须是一个元组,至少包含两个元素,第二个元素必须是整形。

信息可在任何时间进入收件箱(但不包括执行收件箱指令时)。任何新到来的信息都会附加在之前的信息队列之后。

Erros

特定条件会触发报错。当Error Codepoint 是 (0,0,0)的情况下产生报错,则VM进入ErrorStop状态。如果在非(0,0,0)情况下报错则将Current Codepoint设置为Error Codepoint。

如果一条指令产生了错误,该指令在栈上产生的效果为:首先,如果该指令有立即值,该值会被推入栈;然后,如果该指令在非错误的情况下会移除栈中的K条指令,则K条指令现在会被移除(除了该栈会变空的情况,否则会造成栈下溢)。类似地,在没有报错的情况下如果指令会移除AuxStack中L条内容,则L项内容会从AuxStack中移除(除非AuxStack会变空)。

阻塞

某些指令会阻塞,直至某些条件为真。这意味着如果这些条件为假,该指令则无法完成,VM必须处于该指令之前的状态。如果条件为真,VM可以执行该指令。其结果也就是,VM看起来像卡住了,并一直在等待这些条件变为真。

AVMGas

每条指令都会消耗一定量的AVMGas。(Arbitrum整个系统也会使用ArbGas来标定,1 ArbGas = 100 AVMGas.这个1:100的比例是为了显示在Arbitrum UI的数字对用户更易理解。)

指令所消耗的AVMGas可能在未来会有所变更。

当某个指令将要执行时,如果该指令的AVMGas为G:

  • 若AVMGas Remaining < G,AVMGas Remaining被设置为MaxUint256并报错。该指令不会执行。
  • 否则AVMGas Remaining将减去G,指令执行。

指令

处于Halted或ErrorStop状态的VM无法执行任何指令。

处于扩展状态的VM能够执行指令。要执行指令,VM需要从Current Codepoint获取操作码。

如果该操作码不是AVM指令集中的值,系统会以报错操作码的方式执行。

如果操作码有效,但在栈或辅助栈中没有足够的内容条目去执行该操作码,首先先清空二者中要下溢的,然后将其中不会下溢的按照未报错时的情况来移除其中的条目。二者若都下溢则都会被清空。最终,系统会以报错操作码的方式执行。

除了上述情况,VM会执行该操作码的预设行为。

如果在执行操作码的过程中遇到错误,则将该操作码原本应消耗的条目从栈和辅助栈中移除。在下溢的情况中,从栈中移除min(栈大小,消耗条目)。

指令集如下:

Opcode Nickname Semantics AVMGas cost
00s: Arithmetic Operations  
0x01 add Pop two values (A, B) off the Data Stack. If A and B are both Integers, Push the value A+B (truncated to 256 bits) onto the Data Stack. Otherwise, raise an Error. 3
0x02 mul Same as add, except multiply rather than add. 3
0x03 sub Same as add, except subtract rather than add. 3
0x04 div Pop two values (A, B) off the Data Stack. If A and B are both Integers and B is non-zero, Push A/B (unsigned integer divide) onto the Data Stack. Otherwise, raise an Error. 4
0x05 sdiv Pop two values (A, B) off the Data Stack. If A and B are both Integers and B is non-zero, Push A/B (signed integer divide) onto the Data Stack. Otherwise, raise an Error. 7
0x06 mod Same as div, except compute (A mod B), treating A and B as unsigned integers. 4
0x07 smod Same as sdiv, except compute (A mod B), treating A and B as signed integers, rather than doing integer divide. The result is defined to be equal to sgn(A)*(abs(A)%abs(B)), where sgn(x) is 1,0, or -1, if x is positive, zero, or negative, respectively, and abs is absolute value. 7
0x08 addmod Pop three values (A, B, C) off the Data Stack. If A, B, and C are all Integers, and C is not zero, Treating A, B, and C as unsigned integers, Push the value (A+B) % C (calculated without 256-bit truncation until end) onto the Data Stack. Otherwise, raise an Error. 4
0x09 mulmod Same as addmod, except multiply rather than add. 4
0x0a exp Same as add, except exponentiate rather than add. 25
0x0b signextend Pop two values (A, B) off the Data Stack. If A and B are both Integers, (if A<31 (interpreting A as unsigned), sign extend B from (A + 1) * 8 bits to 256 bits and Push the result onto the Data Stack; otherwise push A onto the Data Stack). Otherwise, raise an Error. 7
   
10s: Comparison & Bitwise Logic Operations  
0x10 lt Pop two values (A,B) off the Data Stack. If A and B are both Integers, then (treating A and B as unsigned integers, if A<B, push 1 on the Data Stack; otherwise push 0 on the Data Stack). Otherwise, raise an Error. 2
0x11 gt Same as lt, except greater than rather than less than 2
0x12 slt Pop two values (A,B) off the Data Stack. If A and B are both Integers, then (treating A and B as signed integers, if A<B, push 1 on the Data Stack; otherwise push 0 on the Data Stack). Otherwise, raise an Error. 2
0x13 sgt Same as slt, except greater than rather than less than 2
0x14 eq Pop two values (A, B) off the Data Stack. If A and B have different types, raise an Error. Otherwise if A and B are equal by value, Push 1 on the Data Stack. (Two Tuples are equal by value if they have the same number of slots and are equal by value in every slot.) Otherwise, Push 0 on the Data Stack. 2
0x15 iszero If A is the Integer 0, push 1 onto the Data Stack. Otherwise, if A is a non-zero Integer, push 0 onto the Data Stack. Otherwise (i.e., if A is not an Integer), raise an Error. 1
0x16 and Pop two values (A, B) off the Data Stack. If A and B are both Integers, then push the bitwise and of A and B on the Data Stack. Otherwise, raise an Error. 2
0x17 or Same as and, except bitwise or rather than bitwise and 2
0x18 xor Same as and, except bitwise xor rather than bitwise and 2
0x19 not Pop one value (A) off the Data Stack. If A is an Integer, then push the bitwise negation of A on the Data Stack. Otherwise, raise an Error. 1
0x1a byte Pop two values (A, B) off the Data Stack. If A and B are both Integers, (if A<32 (interpreting A as unsigned), then push the A’th byte of B onto the Data Stack, otherwise push Integer 0 onto the Data Stack). Otherwise, raise an Error. 4
0x1b shl Pop two values (A, B) off the Data Stack. If A and B are both Integers, push B shifted left by A bits. Otherwise, raise an Error. 4
0x1c shr Pop two values (A, B) off the Data Stack. If A and B are both Integers, push B shifted right by A bits. Otherwise, raise an Error. 4
0x1d sar Pop two values (A, B) off the Data Stack. If A and B are both Integers, shift B right by A bits with sign extension. Otherwise, raise an Error. 4
   
20s: Hashing  
0x20 hash Pop a Value (A) off of the Data Stack. Push Hash(A) onto the Data Stack. 7
0x21 type Pop a Value (A) off of the Data Stack. If A is an Integer, Push Integer 0 onto the Data Stack. Otherwise, if A is a Codepoint, Push Integer 1 onto the Data Stack. Otherwise, if A is a Tuple, Push Integer 3 onto the Data Stack. Otherwise (A is a Buffer), Push Integer 12 onto the Data Stack. 3
0x22 ethhash2 Pop two Values (A,B) off of the Data Stack. If A and B are both Integers, convert (big-endian) each of A and B into length-32 byte arrays, concatenate the two into a 64-byte array, compute the Ethereum hash of that byte-array, convert the result into an Integer (big-endian), and Push the resulting Integer onto the Data Stack. Otherwise, raise an Error. 8
0x23 keccakf Pop a Value A off of the Data Stack. If A is a Tuple containing seven Integers, apply the keccakf function, as defined below, and Push the result (which will be a Tuple containing seven Integers) onto the Data Stack. Otherwise, raise an Error. 600
0x24 sha256f Pop three Values (A, B, C) off of the Data Stack. If A, B, and C are all Integers, apply the sha256f function, as defined below, and Push the result (which will be a Integer) onto the Data Stack. Otherwise, raise an Error. 250
   
30s: Stack, Memory, Storage and Flow Operations  
0x30 pop Pop one value off of the Data Stack, and discard that value. 1
0x31 spush Push a copy of Static onto the Data Stack. 1
0x32 rpush Push a copy of Register onto the Data Stack. 1
0x33 rset Pop a Value (A) off of the Data Stack. Set Register to A. 2
0x34 jump Pop one value (A) off of the Data Stack. If A is a Codepoint, set the Instruction Stack to A. Otherwise raise an Error. 4
0x35 cjump Pop two values (A, B) off of the Data Stack. If A is not a Codepoint or B is not an Integer, raise an Error. Otherwise (If B is zero, do Nothing. Otherwise set the Instruction Stack to A.). 4
0x36 stackempty If the Data Stack is empty, Push 1 on the Data Stack, otherwise Push 0 on the Data Stack. 2
0x37 pcpush Push the Codepoint of the currently executing operation to the Data Stack. 1
0x38 auxpush Pop one value off the Data Stack, and push it to the Aux Stack. 1
0x39 auxpop Pop one value off the Aux Stack, and push it to the Data Stack. 1
0x3a auxstackempty If the Aux Stack is empty, Push 1 on the Data Stack, otherwise Push 0 on the Data Stack. 2
0x3b nop Do nothing. 1
0x3c errpush Push a copy of the Error Codepoint onto the Data Stack. 1
0x3d errset Pop a Value (A) off of the Data Stack. Set the Error Codepoint to A. 1
   
40s: Duplication and Exchange Operations  
0x40 dup0 Pop one value (A) off of the Data Stack. Push A onto the Data Stack. Push A onto the Data Stack. 1
0x41 dup1 Pop two values (A,B) off the Data Stack. Push B,A,B onto the Data Stack, in that order. 1
0x42 dup2 Pop three values (A,B,C) off the Data Stack. Push C,B,A,C onto the Data Stack, in that order. 1
0x43 swap1 Pop two values (A,B) off the Data Stack. Push A onto the Data Stack. Push B onto the Data Stack. 1
0x44 swap2 Pop three values (A,B,C) off the data Stack. Push A,B,C onto the Data Stack, in that order. 1
   
50s: Tuple Operations  
0x50 tget Pop two values (A,B) off the Data Stack. If B is a Tuple, and A is an integer, and A>=0 and A is less than length(B), then Push the value in the A_th slot of B onto the Data Stack. Otherwise raise an Error. 2
0x51 tset Pop three values (A,B,C) off of the Data Stack. If B is a Tuple, and A is an Integer, and A>=0, and A is less than length(B), then create a new Tuple that is identical to B, except that slot A has been set to C, then Push the new Tuple onto the Data Stack. Otherwise, raise an Error. 40
0x52 tlen Pop a value (A) off the Data Stack. If A is a Tuple, push the length of A (i.e. the number of slots in A) onto the Data Stack. Otherwise, raise an Error. 2
0x53 xget Pop one value (A) off the Data Stack and one value (B) off the Aux Stack. If B is a Tuple, and A is an integer, and A>=0 and A is less than length(B), then Push the value in the A_th slot of B onto the Data Stack and push B back onto the Aux Stack. Otherwise raise an Error. 3
0x54 xset Pop three values (A,B) off of the Data Stack and one value (C) off the Aux Stack. If C is a Tuple, and A is an Integer, and A>=0, and A is less than length(C), then create a new Tuple that is identical to C, except that slot A has been set to B, then Push the new Tuple onto the Aux Stack. Otherwise, raise an Error. 41
   
60s: Logging Operations  
0x60 breakpoint In an AVM emulator, return control to the Runtime Environment. 100
0x61 log Pop a Value (A) off the Data Stack, and convey A to the Runtime Environment as a log event. 100
   
70s: System operations  
0x70 send Pop two values (A,B) off the Data Stack. If A is not an integer, B is not a buffer, the length of B is greater than A, A is greater than SEND_SIZE_LIMIT, or A is zero, raise an error. Otherwise, tell the Runtime Environment to publish B extended to length A with zeroes as an outgoing message of this VM. 100
0x71 inboxpeek Pop a Value (A) off the Data Stack. If A is not an integer, raise an Error. Otherwise if the Pending Message is the empty Tuple then (block until the VM’s inbox sequence is non-empty, then remove the first item from the inbox sequence as supplied by the Runtime Environment and set the Pending Message equal to it). Then if A equals the second value in the Pending Message Tuple, Push 1 onto the Data Stack, otherwise push 0 onto the Data Stack. 40
0x72 inbox If the Pending Message is not the empty Tuple, push the Pending Message onto the Data Stack and then set the Pending Message equal to the empty Tuple. Otherwise, block until the VM’s inbox sequence is non-empty. Then remove the first item from the inbox sequence as supplied by the Runtime Environment and push the result onto the Data Stack. 40
0x73 error Raise an Error. 5
0x74 halt Enter the Halted state. 10
0x75 setgas Pop a Value (A) off of the Data Stack. If A is an Integer, write A to the AVMGasRemaining register. Otherwise, raise an Error. 1
0x76 pushgas Push the current value of AVMGasRemaining onto the Data Stack. 1
0x77 errcodepoint Push the error code point to the data stack. 25
0x78 pushinsn Pop two values (A,B) off the Data Stack. If A is an integer and B is a CodePoint, push a new CodePoint to the Data Stack with opcode A and next CodePoint B. Otherwise raise an Error. 25
0x79 pushinsnimm Pop three values (A,B, C) off the Data Stack. If A is an integer and C is a CodePoint, push a new CodePoint to the Data Stack with opcode A, immediate B, and next CodePoint C. Otherwise raise an Error. 25
0x7b sideload Pop a Value (A) of the Data Stake. If A is an Integer, Push an empty tuple to the stack. Otherwise, raise an Error. 10
80s: Precompile Operations  
0x80 ecrecover Pop four values off the Data Stack. If not all of the values are integers raise an error. The first two values first and second half of a compact ecdsa signature, the third is the recovery ID of the signature, and the forth is the message. If the recovered ethereum address was valid push the address, otherwise push 0. This instruction matches the behavior of the EVM ecrecover opcode, except it expects the recover ID to be a 0 or 1 as opposed to a 27 or 28 in Ethereum. 20000
0x81 ecadd Pop four values (A, B, C, D) off the Datastack. This operation adds two points on the alt_bn128 curve. If not all of the values are integers raise an error. A and B are interpreted as the X and Y coordinates of a point from G1, C and D are interpreted as the X and Y coordinates of a second point. The two points are added resulting in a new point, R. The y coordinate of R is pushed to the Datastack, then the X coordinate or R is pushed to the Datastack. 3500
0x82 ecmul Pop four values (A, B, C, D) off the Datastack. This operation multiplies a point by a scalar on the alt_bn128 curve. If not all of the values are integers raise an error. A and B are interpreted as the X and Y coordinates of a point from G1, C is interpreted as a scalar. The point is multiplied by the scalar resulting in a new point, R. The y coordinate of R is pushed to the Datastack, then the X coordinate or R is pushed to the Datastack. 82000
0x83 ecpairing Pop a value (A) off the Datastack.The Value A is interpreted as a nested stack of 2-Tuples where the first member is a Value and the second member is either a 2-Tuple or and empty Tuple signaling the termination of the stack. If A does not have that form, or there were more than 30 values in the stack, or not all values in the stack were 6-Tuples containing all integers, raise an error. The number of items extracted from the Tuple stack is k. The first and second Tuple elements are the X and Y coordinates of a G1 point, the third and fourth elements are interpreted as the two parts of the X coordinate of a G2 point and the fifth and sixth elements are interpreted as the two parts of the Y coordinate of the G2 point. The alt_bn128 pairing operation is applied to that list of points, and a push a 1 to the Datastack if the result is the one point on alt_bn128, push 0 otherwise. 1000 + 500000*min(k, 30)
0xa0 newbuffer Push an empty buffer to stack 10
0xa1 getbuffer8 Pop two values (A) and (B) off the stack. The value A must be a buffer and B must be an integer smaller than 2**64. If any of these conditions are not met, raise an error. Pushes to the stack Bth byte of buffer A. 10
0xa2 getbuffer64 Pop two values (A) and (B) off the stack. The value A must be a buffer and B must be an integer smaller than 2**64-7. If any of these conditions are not met, raise an error. Pushes to the stack B..B+7 bytes of buffer A as BE integer. 10
0xa3 getbuffer256 Pop two values (A) and (B) off the stack. The value A must be a buffer and B must be an integer smaller than 2**64-31. If any of these conditions are not met, raise an error. Pushes to the stack B..B+31 bytes of buffer A as BE integer. 10
0xa4 setbuffer8 Pop three values (A), (B) and (C) off the stack. The value A must be a buffer, B must be an integer smaller than 264 and C must be an integer smaller than 28. If any of these conditions are not met, raise an error. Pushes to stack a new buffer that is same as A except that byte in position B is now C. 100
0xa5 setbuffer64 Pop three values (A), (B) and (C) off the stack. The value A must be a buffer, B must be an integer smaller than 264-7 and C must be an integer smaller than 264. If any of these conditions are not met, raise an error. Pushes to stack a new buffer that is same as A except that bytes in positions B..B+7 are now BE representation of C. 100
0xa6 setbuffer256 Pop three values (A), (B) and (C) off the stack. The value A must be a buffer, B must be an integer smaller than 2**64-31 and C must be an integer. If any of these conditions are not met, raise an error. Pushes to stack a new buffer that is same as A except that bytes in positions B..B+31 are now BE representation of C. 100

keccakf的定义

keccakf函数是由keccakf指令计算的。该函数以七个整形组成的数组为输入,输出一个七个整形组成的数组。

该函数分为三步。

  1. 使用七个整形组成的数组,得到一个200位的字符串。从 i = 0 至 5 (含), 该结果的 32i32i+31 字节被设为等于 input[i] 的32位大端序形态. 该结果的192-199 字节被设为等于 input[6] % (2**64) 的8位大端序形态.
  2. 以第一步的结果作为输入,使用SHA-3 标准 (FIPS PUB 202, dated August 2015)中的函数KECCAK-p[1600, 24]计算,输出一个200位的字符串。
  3. 使用第二步的结果作为输入,得到一个七位整形的数组。该数组是由keccakf指令生成的。 对于 i = 0 至 5 (含), output[i] 设为等于结果2的 (解析为32位大端序整形) 32i32i+31 字节. output[6] 设置为结果2(解析为一个8位大端序整形 in the range 0 至 (2**64)-1))的 192-199 字节。

sha256f的定义

sha256f 函数由 sha256f 指令计算的. 该函数使用三个整形作为输入,并输出一个整形。

该函数有三步。

  1. 栈的第一项的32位小端序形式解析为摘要,第二和第三项的32位形态串接并解析为输入数组。
  2. 使用第一步中的摘要和输入数组,进行SHA256压缩运算,输出32位字符串。
  3. 使用2的结果作为输入,得出其小端序整形