1. 指令結構

Cairo CPU原生支持的word是一個域元素,而這個域是特徵值大於Cairo - 指令 。每個指令會佔用1到2個word,如果指令後面跟著立即值([ap] = "12345678")則該指令佔用2個word,並且值存在第二個word裡。每個指令的第一個word由以下元素組成:

Cairo - 指令

  • Cairo - 指令 [ bit0..15]:目的地址偏移量,代表值Cairo - 指令
  • Cairo - 指令 [ bit16..31]:op0地址偏移量,代表值Cairo - 指令
  • Cairo - 指令 [ bit32..47]:op1地址偏移量,代表值Cairo - 指令
  • dst reg [ bit48]:目的地址偏移的基寄存器, ap or fp;
  • op0 reg [ bit49]:op0地址偏移的基寄存器, ap or fp;

Cairo - 指令

2. 狀態轉換

狀態轉換函數代表了一個通用的狀態轉換單元(由於它包含了所有指令類型的處理邏輯),而一個計算通常會分解成多個連續執行的指令,因此我們需要:

a. 確保指令的內容,以及指令執行前後的狀態的有效性(比如滿足一定的範圍校驗,和狀態一致性校驗)

b. 確保執行的指令是一個有效的指令

2.1 轉換邏輯

如果指令執行前後的狀態是一致的,那麼其狀態的更新一定是按照以下邏輯執行:

Cairo - 指令

Cairo - 指令

Cairo - 指令

Cairo - 指令

2.2 指令校驗

如圖1所示,一個指令由以下元素組成:

Cairo - 指令

Cairo - 指令

Cairo - 指令

注意:我們並沒有為指令的15bit flags分別分配15個長度為N 的virtual column,而是用一個長度為16N的virtual column Cairo - 指令來表示,它滿足:

Cairo - 指令

3. 指令示例

3.1 斷言相等

斷言相等指令可以用下述語法表示:

Cairo - 指令

它確保了公式兩邊是相等的,否則程序的執行將會被返回。

等式左邊往往來自Cairo - 指令或者Cairo - 指令 ,右邊有一些可能的形式( Cairo - 指令Cairo - 指令可以是fpap可以是加法或乘法, imm可以是任何固定的字段元素):

Cairo - 指令

Note2 :除法和減法可以分別表示為具有不同操作數順序的乘法和加法。

assert指令可以被認為是一條賦值指令,其中一邊是已知的,另一邊是未知的。例如[ap]=4可以被認為是斷言的[ap]值為4,或者根據上下文將[ap]賦值為4。

圖4給出了斷言相等指令的一些示例,以及每個指令對應的標誌值:

Cairo - 指令

解釋指令[fp + 1] = 5:

◦ 為assert指令=> opcode = 4

◦ next_ap = ap => ap_update = 00 = 0

◦ next_pc = pc + instruction_size => pc_update = 000 = 0

◦ op0和op1沒有add or mul => res_logic(res) = 00 = 0

◦ 存在立即數=> op1_src(op1) = 001 = 1

◦ 立即數地址指令地址相鄰=> off_op1 = 1

◦ 等式左邊[fp + 1] => dst_reg(dst) = 1

◦ 等式左邊[fp + 1] => off_dst = 1

◦ op0_reg/ off_op0 => inital value(1/-1) //因為這個指令用不到這些flags,所以填充默認值

3.2 條件和非條件跳轉

jmp 指令允許更改程序計數器pc 的值。

Cairo支持相對跳轉(其操作數代表相對當前pc的偏移)和絕對跳轉- 分別用關鍵字rel和abs表示;jmp指令或許是有條件的,比如當某個內存單元的值不為0時,觸發jmp指令。

指令的語法如下所示:

# Unconditional jumps.

jmp abs < address >

jmp rel < offset >

# Conditional jumps.

jmp rel < offset > if < op >!

圖5給出了jmp 指令的一些示例,以及每個指令對應的標誌值:

Cairo - 指令

解釋指令jmp rel [ap +1] + [fp - 7]:

◦ 為jmp指令=> opcode = 0

◦ next_ap = ap => ap_update = b00 = 0

◦ next_pc = pc + res=> pc_update = b010 = 2

◦ res = op0 + op1 => res_logic(res) = b01 = 1

◦ op1: [fp - 7] => op1_src(op1) = b010 = 2

◦ op1: [fp - 7] => off_op1 = -7

◦ op0: [ap + 1] => op0_src(op0) = 0

◦ op0: [ap + 1] => off_op0 = 1

◦ dst_reg/ off_dst => inital value(1/-1) ///因為這個指令用不到這些flags,所以填充默認值

3.3 call 和ret

call和ret指令允許實現函數堆棧。 call指令更新程序計數器(pc)和幀指針(fp)寄存器。程序計數器的更新類似於jmp 指令。之前fp 的值被寫入[ap] ,以允許ret 指令將fp 的值重置為調用之前的值;類似地,返回的pc (調用指令後面指令的地址)被寫到[ap+1] ,以允許ret 指令跳回並繼續執行調用指令後面的代碼的執行。由於寫入了兩個存儲單元,ap 向前進了2,fp 被設置為新的ap。

指令的語法如下:

call abs < address >

call rel < offset >

ret

圖6給出了call 和ret 指令的一些示例,以及每個指令對應的標誌值:

Cairo - 指令

解釋指令call abs [fp + 4]:

◦ 為call指令=> opcode = 0

◦ next_ap = ap => ap_update = b00 = 0

◦ next_pc = res => pc_update = b001 = 1

◦ res = op1 => res_logic(res) = b00 = 0

◦ op1: [fp + 4] => op1_src(op1) = b010 = 2

◦ op1: [fp + 4] => off_op1 = 4

◦ op0_reg/ off_op0 => inital value(0/1) ///因為這個指令用不到這些flags,所以填充默認值

◦ dst_reg/ off_dst => inital value(0/0) ///因為這個指令用不到這些flags,所以填充默認值

3.4 高級ap

指令ap + = < op > 通過給定的操作數增加ap 的值。

圖7給出了高級ap 指令的一些示,以及每個指令對應的標誌:

Cairo - 指令

解釋指令ap += 123:

◦ 為advancing ap指令=> opcode = 0

◦ next_ap = ap + res => ap_update = b01 = 1

◦ next_pc = pc + instruction_size => pc_update = b000 = 0

◦ res = op1 => res_logic(res) = b00 = 0

◦ op1 = 123 => op1_src(op1) = b001 = 1

◦ op1 = 123 => off_op1 = 1

◦ op0_reg/ off_op0 => inital value(1/-1) ///因為這個指令用不到這些flags,所以填充默認值

◦ dst_reg/ off_dst => inital value(1/-1) ///因為這個指令用不到這些flags,所以填充默認值

參考

Specification for Cairo:https://arxiv.org/pdf/2109.14534.pdf

關於我們

Sin7Y成立於2021年,由頂尖的區塊鏈開發者和密碼學工程師組成。我們既是項目孵化器也是區塊鏈技術研究團隊,探索EVM、Layer2、跨鏈、隱私計算、自主支付解決方案等最重要和最前沿的技術。

微信公眾號:Sin7Y

GitHub:Sin7Y

Twitter:@Sin7Y_Labs

Medium:Sin7Y

Mirror:Sin7Y

HackMD:Sin7Y

HackerNoon:Sin7Y

Email:contact@sin7y.org