本文档以非正式的方式描述了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也是一个栈。
序列化一种可逆的从值到字节数组的映射。在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状态不外乎这几种:特殊状态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是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。
每个在收件箱序列中的值都必须是一个元组,至少包含两个元素,第二个元素必须是整形。
信息可在任何时间进入收件箱(但不包括执行收件箱指令时)。任何新到来的信息都会附加在之前的信息队列之后。
特定条件会触发报错。当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。(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
指令计算的。该函数以七个整形组成的数组为输入,输出一个七个整形组成的数组。
该函数分为三步。
- 使用七个整形组成的数组,得到一个200位的字符串。从 i = 0 至 5 (含), 该结果的 32i 到 32i+31 字节被设为等于 input[i] 的32位大端序形态. 该结果的192-199 字节被设为等于 input[6] % (2**64) 的8位大端序形态.
- 以第一步的结果作为输入,使用SHA-3 标准 (FIPS PUB 202, dated August 2015)中的函数KECCAK-p[1600, 24]计算,输出一个200位的字符串。
- 使用第二步的结果作为输入,得到一个七位整形的数组。该数组是由
keccakf
指令生成的。 对于 i = 0 至 5 (含), output[i] 设为等于结果2的 (解析为32位大端序整形) 32i 至 32i+31 字节. output[6] 设置为结果2(解析为一个8位大端序整形 in the range 0 至 (2**64)-1))的 192-199 字节。
sha256f
函数由 sha256f
指令计算的. 该函数使用三个整形作为输入,并输出一个整形。
该函数有三步。
- 栈的第一项的32位小端序形式解析为摘要,第二和第三项的32位形态串接并解析为输入数组。
- 使用第一步中的摘要和输入数组,进行SHA256压缩运算,输出32位字符串。
- 使用2的结果作为输入,得出其小端序整形