1. 指令結構
Cairo CPU原生支持的word是一個域元素,而這個域是特徵值大於 。每個指令會佔用1到2個word,如果指令後面跟著立即值([ap] = "12345678")則該指令佔用2個word,並且值存在第二個word裡。每個指令的第一個word由以下元素組成:
- [ bit0..15]:目的地址偏移量,代表值
- [ bit16..31]:op0地址偏移量,代表值
- [ bit32..47]:op1地址偏移量,代表值
- dst reg [ bit48]:目的地址偏移的基寄存器, ap or fp;
- op0 reg [ bit49]:op0地址偏移的基寄存器, ap or fp;
2. 狀態轉換
狀態轉換函數代表了一個通用的狀態轉換單元(由於它包含了所有指令類型的處理邏輯),而一個計算通常會分解成多個連續執行的指令,因此我們需要:
a. 確保指令的內容,以及指令執行前後的狀態的有效性(比如滿足一定的範圍校驗,和狀態一致性校驗)
b. 確保執行的指令是一個有效的指令
2.1 轉換邏輯
如果指令執行前後的狀態是一致的,那麼其狀態的更新一定是按照以下邏輯執行:
2.2 指令校驗
如圖1所示,一個指令由以下元素組成:
注意:我們並沒有為指令的15bit flags分別分配15個長度為N 的virtual column,而是用一個長度為16N的virtual column 來表示,它滿足:
3. 指令示例
3.1 斷言相等
斷言相等指令可以用下述語法表示:
它確保了公式兩邊是相等的,否則程序的執行將會被返回。
等式左邊往往來自或者 ,右邊有一些可能的形式( 和可以是fp或ap , ∘可以是加法或乘法, imm可以是任何固定的字段元素):
Note2 :除法和減法可以分別表示為具有不同操作數順序的乘法和加法。
assert指令可以被認為是一條賦值指令,其中一邊是已知的,另一邊是未知的。例如[ap]=4可以被認為是斷言的[ap]值為4,或者根據上下文將[ap]賦值為4。
圖4給出了斷言相等指令的一些示例,以及每個指令對應的標誌值:
解釋指令[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 指令的一些示例,以及每個指令對應的標誌值:
解釋指令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 指令的一些示例,以及每個指令對應的標誌值:
解釋指令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 指令的一些示,以及每個指令對應的標誌:
解釋指令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