use miden_core::{FMP_ADDR, FMP_INIT_VALUE, field::PrimeCharacteristicRing, operations::opcodes};
use miden_crypto::stark::air::{ExtensionBuilder, LiftedAirBuilder, WindowAccess};
use crate::{
Felt, MainTraceRow,
constraints::{
bus::indices::B_CHIPLETS,
chiplets::{bitwise::P_BITWISE_K_TRANSITION, hasher},
op_flags::OpFlags,
tagging::{TaggingAirBuilderExt, ids::TAG_CHIPLETS_BUS_BASE},
},
trace::{
Challenges,
chiplets::{
NUM_ACE_SELECTORS, NUM_KERNEL_ROM_SELECTORS,
ace::{
ACE_INIT_LABEL, CLK_IDX, CTX_IDX, ID_0_IDX, PTR_IDX, READ_NUM_EVAL_IDX,
SELECTOR_START_IDX,
},
bitwise::{self, BITWISE_AND_LABEL, BITWISE_XOR_LABEL},
hasher::{
HASH_CYCLE_LEN, LINEAR_HASH_LABEL, MP_VERIFY_LABEL, MR_UPDATE_NEW_LABEL,
MR_UPDATE_OLD_LABEL, RETURN_HASH_LABEL, RETURN_STATE_LABEL,
},
kernel_rom::{KERNEL_PROC_CALL_LABEL, KERNEL_PROC_INIT_LABEL},
memory::{
MEMORY_READ_ELEMENT_LABEL, MEMORY_READ_WORD_LABEL, MEMORY_WRITE_ELEMENT_LABEL,
MEMORY_WRITE_WORD_LABEL,
},
},
decoder::{ADDR_COL_IDX, HASHER_STATE_RANGE, USER_OP_HELPERS_OFFSET},
log_precompile::{
HELPER_ADDR_IDX, HELPER_CAP_PREV_RANGE, STACK_CAP_NEXT_RANGE, STACK_COMM_RANGE,
STACK_R0_RANGE, STACK_R1_RANGE, STACK_TAG_RANGE,
},
},
};
const CHIPLET_BUS_ID: usize = TAG_CHIPLETS_BUS_BASE;
const CHIPLET_BUS_NAMESPACE: &str = "chiplets.bus.chiplets.transition";
pub fn enforce_chiplets_bus_constraint<AB>(
builder: &mut AB,
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
op_flags: &OpFlags<AB::Expr>,
challenges: &Challenges<AB::ExprEF>,
) where
AB: LiftedAirBuilder<F = Felt>,
{
let (b_local_val, b_next_val) = {
let aux = builder.permutation();
let aux_local = aux.current_slice();
let aux_next = aux.next_slice();
(aux_local[B_CHIPLETS], aux_next[B_CHIPLETS])
};
let f_hperm: AB::Expr = op_flags.hperm();
let f_mpverify: AB::Expr = op_flags.mpverify();
let f_mrupdate: AB::Expr = op_flags.mrupdate();
let f_join: AB::Expr = op_flags.join();
let f_split: AB::Expr = op_flags.split();
let f_loop: AB::Expr = op_flags.loop_op();
let f_call: AB::Expr = op_flags.call();
let f_dyn: AB::Expr = op_flags.dyn_op();
let f_dyncall: AB::Expr = op_flags.dyncall();
let f_syscall: AB::Expr = op_flags.syscall();
let f_span: AB::Expr = op_flags.span();
let f_respan: AB::Expr = op_flags.respan();
let f_end: AB::Expr = op_flags.end();
let f_mload: AB::Expr = op_flags.mload();
let f_mstore: AB::Expr = op_flags.mstore();
let f_mloadw: AB::Expr = op_flags.mloadw();
let f_mstorew: AB::Expr = op_flags.mstorew();
let f_hornerbase: AB::Expr = op_flags.hornerbase();
let f_hornerext: AB::Expr = op_flags.hornerext();
let f_mstream: AB::Expr = op_flags.mstream();
let f_pipe: AB::Expr = op_flags.pipe();
let f_cryptostream: AB::Expr = op_flags.cryptostream();
let f_u32and: AB::Expr = op_flags.u32and();
let f_u32xor: AB::Expr = op_flags.u32xor();
let f_evalcircuit: AB::Expr = op_flags.evalcircuit();
let f_logprecompile: AB::Expr = op_flags.log_precompile();
let v_hperm = compute_hperm_request::<AB>(local, next, challenges);
let v_mpverify = compute_mpverify_request::<AB>(local, challenges);
let v_mrupdate = compute_mrupdate_request::<AB>(local, next, challenges);
let v_join = compute_control_block_request::<AB>(local, next, challenges, ControlBlockOp::Join);
let v_split =
compute_control_block_request::<AB>(local, next, challenges, ControlBlockOp::Split);
let v_loop = compute_control_block_request::<AB>(local, next, challenges, ControlBlockOp::Loop);
let v_call = compute_call_request::<AB>(local, next, challenges);
let v_dyn = compute_dyn_request::<AB>(local, next, challenges);
let v_dyncall = compute_dyncall_request::<AB>(local, next, challenges);
let v_syscall = compute_syscall_request::<AB>(local, next, challenges);
let v_span = compute_span_request::<AB>(local, next, challenges);
let v_respan = compute_respan_request::<AB>(local, next, challenges);
let v_end = compute_end_request::<AB>(local, challenges);
let v_mload = compute_memory_element_request::<AB>(local, next, challenges, true); let v_mstore = compute_memory_element_request::<AB>(local, next, challenges, false); let v_mloadw = compute_memory_word_request::<AB>(local, next, challenges, true); let v_mstorew = compute_memory_word_request::<AB>(local, next, challenges, false); let v_hornerbase = compute_hornerbase_request::<AB>(local, challenges);
let v_hornerext = compute_hornerext_request::<AB>(local, challenges);
let v_mstream = compute_mstream_request::<AB>(local, next, challenges);
let v_pipe = compute_pipe_request::<AB>(local, next, challenges);
let v_cryptostream = compute_cryptostream_request::<AB>(local, next, challenges);
let v_u32and = compute_bitwise_request::<AB>(local, next, challenges, false); let v_u32xor = compute_bitwise_request::<AB>(local, next, challenges, true);
let v_evalcircuit = compute_ace_request::<AB>(local, challenges);
let v_logprecompile = compute_log_precompile_request::<AB>(local, next, challenges);
let request_flag_sum: AB::Expr = f_hperm.clone()
+ f_mpverify.clone()
+ f_mrupdate.clone()
+ f_join.clone()
+ f_split.clone()
+ f_loop.clone()
+ f_call.clone()
+ f_dyn.clone()
+ f_dyncall.clone()
+ f_syscall.clone()
+ f_span.clone()
+ f_respan.clone()
+ f_end.clone()
+ f_mload.clone()
+ f_mstore.clone()
+ f_mloadw.clone()
+ f_mstorew.clone()
+ f_hornerbase.clone()
+ f_hornerext.clone()
+ f_mstream.clone()
+ f_pipe.clone()
+ f_cryptostream.clone()
+ f_u32and.clone()
+ f_u32xor.clone()
+ f_evalcircuit.clone()
+ f_logprecompile.clone();
let one_ef = AB::ExprEF::ONE;
let requests: AB::ExprEF = v_hperm * f_hperm.clone()
+ v_mpverify * f_mpverify.clone()
+ v_mrupdate * f_mrupdate.clone()
+ v_join * f_join.clone()
+ v_split * f_split.clone()
+ v_loop * f_loop.clone()
+ v_call * f_call.clone()
+ v_dyn * f_dyn.clone()
+ v_dyncall * f_dyncall.clone()
+ v_syscall * f_syscall.clone()
+ v_span * f_span.clone()
+ v_respan * f_respan.clone()
+ v_end * f_end.clone()
+ v_mload * f_mload.clone()
+ v_mstore * f_mstore.clone()
+ v_mloadw * f_mloadw.clone()
+ v_mstorew * f_mstorew.clone()
+ v_hornerbase * f_hornerbase.clone()
+ v_hornerext * f_hornerext.clone()
+ v_mstream * f_mstream.clone()
+ v_pipe * f_pipe.clone()
+ v_cryptostream * f_cryptostream.clone()
+ v_u32and * f_u32and.clone()
+ v_u32xor * f_u32xor.clone()
+ v_evalcircuit * f_evalcircuit.clone()
+ v_logprecompile * f_logprecompile.clone()
+ (one_ef.clone() - request_flag_sum);
let (cycle_row_0, cycle_row_31, k_transition) = {
let p = builder.periodic_values();
let cycle_row_0: AB::Expr = p[hasher::periodic::P_CYCLE_ROW_0].into();
let cycle_row_31: AB::Expr = p[hasher::periodic::P_CYCLE_ROW_31].into();
let k_transition: AB::Expr = p[P_BITWISE_K_TRANSITION].into();
(cycle_row_0, cycle_row_31, k_transition)
};
let chiplet_s0: AB::Expr = local.chiplets[0].clone().into();
let chiplet_s1: AB::Expr = local.chiplets[1].clone().into();
let chiplet_s2: AB::Expr = local.chiplets[2].clone().into();
let chiplet_s3: AB::Expr = local.chiplets[3].clone().into();
let chiplet_s4: AB::Expr = local.chiplets[4].clone().into();
let is_bitwise_row: AB::Expr = chiplet_s0.clone() * (AB::Expr::ONE - chiplet_s1.clone());
let is_bitwise_responding: AB::Expr = is_bitwise_row * (AB::Expr::ONE - k_transition);
let is_memory: AB::Expr =
chiplet_s0.clone() * chiplet_s1.clone() * (AB::Expr::ONE - chiplet_s2.clone());
let is_ace_row: AB::Expr = chiplet_s0.clone()
* chiplet_s1.clone()
* chiplet_s2.clone()
* (AB::Expr::ONE - chiplet_s3.clone());
let ace_start_selector: AB::Expr =
local.chiplets[NUM_ACE_SELECTORS + SELECTOR_START_IDX].clone().into();
let is_ace: AB::Expr = is_ace_row * ace_start_selector;
let is_kernel_rom: AB::Expr = chiplet_s0.clone()
* chiplet_s1.clone()
* chiplet_s2.clone()
* chiplet_s3.clone()
* (AB::Expr::ONE - chiplet_s4.clone());
let hasher_response =
compute_hasher_response::<AB>(local, next, challenges, cycle_row_0, cycle_row_31);
let v_bitwise = compute_bitwise_response::<AB>(local, challenges);
let v_memory = compute_memory_response::<AB>(local, challenges);
let v_ace = compute_ace_response::<AB>(local, challenges);
let v_kernel_rom = compute_kernel_rom_response::<AB>(local, challenges);
let responses: AB::ExprEF = hasher_response.sum
+ v_bitwise * is_bitwise_responding.clone()
+ v_memory * is_memory.clone()
+ v_ace * is_ace.clone()
+ v_kernel_rom * is_kernel_rom.clone()
+ (AB::ExprEF::ONE
- hasher_response.flag_sum
- is_bitwise_responding
- is_memory
- is_ace
- is_kernel_rom);
let lhs: AB::ExprEF = Into::<AB::ExprEF>::into(b_next_val) * requests;
let rhs: AB::ExprEF = Into::<AB::ExprEF>::into(b_local_val) * responses;
builder.tagged(CHIPLET_BUS_ID, CHIPLET_BUS_NAMESPACE, |builder| {
builder.when_transition().assert_zero_ext(lhs - rhs);
});
}
fn compute_bitwise_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
is_xor: bool,
) -> AB::ExprEF {
let label: Felt = if is_xor { BITWISE_XOR_LABEL } else { BITWISE_AND_LABEL };
let label: AB::Expr = AB::Expr::from(label);
let a: AB::Expr = local.stack[0].clone().into();
let b: AB::Expr = local.stack[1].clone().into();
let z: AB::Expr = next.stack[0].clone().into();
challenges.encode([label, a, b, z])
}
fn compute_bitwise_response<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
use crate::trace::chiplets::NUM_BITWISE_SELECTORS;
let bw_offset = NUM_BITWISE_SELECTORS;
let sel: AB::Expr = local.chiplets[bw_offset].clone().into();
let one_minus_sel = AB::Expr::ONE - sel.clone();
let label = one_minus_sel * AB::Expr::from(BITWISE_AND_LABEL)
+ sel.clone() * AB::Expr::from(BITWISE_XOR_LABEL);
let a: AB::Expr = local.chiplets[bw_offset + bitwise::A_COL_IDX].clone().into();
let b: AB::Expr = local.chiplets[bw_offset + bitwise::B_COL_IDX].clone().into();
let z: AB::Expr = local.chiplets[bw_offset + bitwise::OUTPUT_COL_IDX].clone().into();
challenges.encode([label, a, b, z])
}
fn compute_memory_word_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
is_read: bool,
) -> AB::ExprEF {
let label = if is_read {
MEMORY_READ_WORD_LABEL
} else {
MEMORY_WRITE_WORD_LABEL
};
let label: AB::Expr = AB::Expr::from_u16(label as u16);
let ctx: AB::Expr = local.ctx.clone().into();
let clk: AB::Expr = local.clk.clone().into();
let addr: AB::Expr = local.stack[0].clone().into();
let (w0, w1, w2, w3) = if is_read {
(
next.stack[0].clone().into(),
next.stack[1].clone().into(),
next.stack[2].clone().into(),
next.stack[3].clone().into(),
)
} else {
(
local.stack[1].clone().into(),
local.stack[2].clone().into(),
local.stack[3].clone().into(),
local.stack[4].clone().into(),
)
};
challenges.encode([label, ctx, addr, clk, w0, w1, w2, w3])
}
fn compute_memory_element_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
is_read: bool,
) -> AB::ExprEF {
let label = if is_read {
MEMORY_READ_ELEMENT_LABEL
} else {
MEMORY_WRITE_ELEMENT_LABEL
};
let label: AB::Expr = AB::Expr::from_u16(label as u16);
let ctx: AB::Expr = local.ctx.clone().into();
let clk: AB::Expr = local.clk.clone().into();
let addr: AB::Expr = local.stack[0].clone().into();
let element = if is_read {
next.stack[0].clone().into()
} else {
local.stack[1].clone().into()
};
challenges.encode([label, ctx, addr, clk, element])
}
fn compute_mstream_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let label: AB::Expr = AB::Expr::from_u16(MEMORY_READ_WORD_LABEL as u16);
let ctx: AB::Expr = local.ctx.clone().into();
let clk: AB::Expr = local.clk.clone().into();
let addr: AB::Expr = local.stack[12].clone().into();
let four: AB::Expr = AB::Expr::from_u16(4);
let word1 = [
next.stack[0].clone().into(),
next.stack[1].clone().into(),
next.stack[2].clone().into(),
next.stack[3].clone().into(),
];
let word2 = [
next.stack[4].clone().into(),
next.stack[5].clone().into(),
next.stack[6].clone().into(),
next.stack[7].clone().into(),
];
let msg1 = challenges.encode([
label.clone(),
ctx.clone(),
addr.clone(),
clk.clone(),
word1[0].clone(),
word1[1].clone(),
word1[2].clone(),
word1[3].clone(),
]);
let msg2 = challenges.encode([
label,
ctx,
addr + four.clone(),
clk,
word2[0].clone(),
word2[1].clone(),
word2[2].clone(),
word2[3].clone(),
]);
msg1 * msg2
}
fn compute_pipe_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let label: AB::Expr = AB::Expr::from_u16(MEMORY_WRITE_WORD_LABEL as u16);
let ctx: AB::Expr = local.ctx.clone().into();
let clk: AB::Expr = local.clk.clone().into();
let addr: AB::Expr = local.stack[12].clone().into();
let four: AB::Expr = AB::Expr::from_u16(4);
let word1 = [
next.stack[0].clone().into(),
next.stack[1].clone().into(),
next.stack[2].clone().into(),
next.stack[3].clone().into(),
];
let word2 = [
next.stack[4].clone().into(),
next.stack[5].clone().into(),
next.stack[6].clone().into(),
next.stack[7].clone().into(),
];
let msg1 = challenges.encode([
label.clone(),
ctx.clone(),
addr.clone(),
clk.clone(),
word1[0].clone(),
word1[1].clone(),
word1[2].clone(),
word1[3].clone(),
]);
let msg2 = challenges.encode([
label,
ctx,
addr + four.clone(),
clk,
word2[0].clone(),
word2[1].clone(),
word2[2].clone(),
word2[3].clone(),
]);
msg1 * msg2
}
fn compute_cryptostream_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let read_label: AB::Expr = AB::Expr::from_u16(MEMORY_READ_WORD_LABEL as u16);
let write_label: AB::Expr = AB::Expr::from_u16(MEMORY_WRITE_WORD_LABEL as u16);
let ctx: AB::Expr = local.ctx.clone().into();
let clk: AB::Expr = local.clk.clone().into();
let src: AB::Expr = local.stack[12].clone().into();
let dst: AB::Expr = local.stack[13].clone().into();
let four: AB::Expr = AB::Expr::from_u16(4);
let rate: [AB::Expr; 8] = core::array::from_fn(|i| local.stack[i].clone().into());
let cipher: [AB::Expr; 8] = core::array::from_fn(|i| next.stack[i].clone().into());
let plain: [AB::Expr; 8] = core::array::from_fn(|i| cipher[i].clone() - rate[i].clone());
let read_msg1 = challenges.encode([
read_label.clone(),
ctx.clone(),
src.clone(),
clk.clone(),
plain[0].clone(),
plain[1].clone(),
plain[2].clone(),
plain[3].clone(),
]);
let read_msg2 = challenges.encode([
read_label,
ctx.clone(),
src + four.clone(),
clk.clone(),
plain[4].clone(),
plain[5].clone(),
plain[6].clone(),
plain[7].clone(),
]);
let write_msg1 = challenges.encode([
write_label.clone(),
ctx.clone(),
dst.clone(),
clk.clone(),
cipher[0].clone(),
cipher[1].clone(),
cipher[2].clone(),
cipher[3].clone(),
]);
let write_msg2 = challenges.encode([
write_label,
ctx,
dst + four,
clk,
cipher[4].clone(),
cipher[5].clone(),
cipher[6].clone(),
cipher[7].clone(),
]);
read_msg1 * read_msg2 * write_msg1 * write_msg2
}
fn compute_hornerbase_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let label: AB::Expr = AB::Expr::from_u16(MEMORY_READ_ELEMENT_LABEL as u16);
let ctx: AB::Expr = local.ctx.clone().into();
let clk: AB::Expr = local.clk.clone().into();
let addr: AB::Expr = local.stack[13].clone().into();
let one: AB::Expr = AB::Expr::ONE;
let helper0_idx = USER_OP_HELPERS_OFFSET;
let helper1_idx = helper0_idx + 1;
let eval0: AB::Expr = local.decoder[helper0_idx].clone().into();
let eval1: AB::Expr = local.decoder[helper1_idx].clone().into();
let msg0 = challenges.encode([label.clone(), ctx.clone(), addr.clone(), clk.clone(), eval0]);
let msg1 = challenges.encode([label, ctx, addr + one, clk, eval1]);
msg0 * msg1
}
fn compute_hornerext_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let label: AB::Expr = AB::Expr::from_u16(MEMORY_READ_WORD_LABEL as u16);
let ctx: AB::Expr = local.ctx.clone().into();
let clk: AB::Expr = local.clk.clone().into();
let addr: AB::Expr = local.stack[13].clone().into();
let base = USER_OP_HELPERS_OFFSET;
let word = [
local.decoder[base].clone().into(),
local.decoder[base + 1].clone().into(),
local.decoder[base + 2].clone().into(),
local.decoder[base + 3].clone().into(),
];
challenges.encode([
label,
ctx,
addr,
clk,
word[0].clone(),
word[1].clone(),
word[2].clone(),
word[3].clone(),
])
}
fn compute_memory_response<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
use crate::trace::chiplets::{NUM_MEMORY_SELECTORS, memory};
let mem_offset = NUM_MEMORY_SELECTORS;
let is_read: AB::Expr = local.chiplets[mem_offset + memory::IS_READ_COL_IDX].clone().into();
let is_word: AB::Expr =
local.chiplets[mem_offset + memory::IS_WORD_ACCESS_COL_IDX].clone().into();
let ctx: AB::Expr = local.chiplets[mem_offset + memory::CTX_COL_IDX].clone().into();
let word: AB::Expr = local.chiplets[mem_offset + memory::WORD_COL_IDX].clone().into();
let idx0: AB::Expr = local.chiplets[mem_offset + memory::IDX0_COL_IDX].clone().into();
let idx1: AB::Expr = local.chiplets[mem_offset + memory::IDX1_COL_IDX].clone().into();
let clk: AB::Expr = local.chiplets[mem_offset + memory::CLK_COL_IDX].clone().into();
let addr: AB::Expr = word + idx1.clone() * AB::Expr::from_u16(2) + idx0.clone();
let one = AB::Expr::ONE;
let write_element_label = AB::Expr::from_u16(MEMORY_WRITE_ELEMENT_LABEL as u16);
let write_word_label = AB::Expr::from_u16(MEMORY_WRITE_WORD_LABEL as u16);
let read_element_label = AB::Expr::from_u16(MEMORY_READ_ELEMENT_LABEL as u16);
let read_word_label = AB::Expr::from_u16(MEMORY_READ_WORD_LABEL as u16);
let write_label =
(one.clone() - is_word.clone()) * write_element_label + is_word.clone() * write_word_label;
let read_label =
(one.clone() - is_word.clone()) * read_element_label + is_word.clone() * read_word_label;
let label = (one.clone() - is_read.clone()) * write_label + is_read.clone() * read_label;
let v0: AB::Expr = local.chiplets[mem_offset + memory::V_COL_RANGE.start].clone().into();
let v1: AB::Expr = local.chiplets[mem_offset + memory::V_COL_RANGE.start + 1].clone().into();
let v2: AB::Expr = local.chiplets[mem_offset + memory::V_COL_RANGE.start + 2].clone().into();
let v3: AB::Expr = local.chiplets[mem_offset + memory::V_COL_RANGE.start + 3].clone().into();
let element: AB::Expr =
v0.clone() * (one.clone() - idx0.clone()) * (one.clone() - idx1.clone())
+ v1.clone() * idx0.clone() * (one.clone() - idx1.clone())
+ v2.clone() * (one.clone() - idx0.clone()) * idx1.clone()
+ v3.clone() * idx0.clone() * idx1.clone();
let is_element = one.clone() - is_word.clone();
let element_msg =
challenges.encode([label.clone(), ctx.clone(), addr.clone(), clk.clone(), element]);
let word_msg = challenges.encode([label, ctx, addr, clk, v0, v1, v2, v3]);
element_msg * is_element + word_msg * is_word
}
struct HasherResponse<EF, E> {
sum: EF,
flag_sum: E,
}
fn compute_hasher_response<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
cycle_row_0: AB::Expr,
cycle_row_31: AB::Expr,
) -> HasherResponse<AB::ExprEF, AB::Expr> {
use crate::trace::{
CHIPLETS_OFFSET,
chiplets::{HASHER_NODE_INDEX_COL_IDX, HASHER_STATE_COL_RANGE},
};
let one = AB::Expr::ONE;
let hasher_active: AB::Expr = one.clone() - local.chiplets[0].clone().into();
let hs0: AB::Expr = local.chiplets[1].clone().into();
let hs1: AB::Expr = local.chiplets[2].clone().into();
let hs2: AB::Expr = local.chiplets[3].clone().into();
let f_bp = hasher_active.clone()
* cycle_row_0.clone()
* hs0.clone()
* (one.clone() - hs1.clone())
* (one.clone() - hs2.clone());
let f_mp = hasher_active.clone()
* cycle_row_0.clone()
* hs0.clone()
* (one.clone() - hs1.clone())
* hs2.clone();
let f_mv = hasher_active.clone()
* cycle_row_0.clone()
* hs0.clone()
* hs1.clone()
* (one.clone() - hs2.clone());
let f_mu =
hasher_active.clone() * cycle_row_0.clone() * hs0.clone() * hs1.clone() * hs2.clone();
let f_hout = hasher_active.clone()
* cycle_row_31.clone()
* (one.clone() - hs0.clone())
* (one.clone() - hs1.clone())
* (one.clone() - hs2.clone());
let f_sout = hasher_active.clone()
* cycle_row_31.clone()
* (one.clone() - hs0.clone())
* (one.clone() - hs1.clone())
* hs2.clone();
let f_abp = hasher_active.clone()
* cycle_row_31.clone()
* hs0.clone()
* (one.clone() - hs1.clone())
* (one.clone() - hs2.clone());
let state: [AB::Expr; 12] = core::array::from_fn(|i| {
let col_idx = HASHER_STATE_COL_RANGE.start - CHIPLETS_OFFSET + i;
local.chiplets[col_idx].clone().into()
});
let node_index: AB::Expr =
local.chiplets[HASHER_NODE_INDEX_COL_IDX - CHIPLETS_OFFSET].clone().into();
let state_next: [AB::Expr; 12] = core::array::from_fn(|i| {
let col_idx = HASHER_STATE_COL_RANGE.start - CHIPLETS_OFFSET + i;
next.chiplets[col_idx].clone().into()
});
let node_index_next: AB::Expr =
next.chiplets[HASHER_NODE_INDEX_COL_IDX - CHIPLETS_OFFSET].clone().into();
let addr_next: AB::Expr = local.clk.clone().into() + one.clone();
let label_bp = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 16);
let label_mp = AB::Expr::from_u16(MP_VERIFY_LABEL as u16 + 16);
let label_mv = AB::Expr::from_u16(MR_UPDATE_OLD_LABEL as u16 + 16);
let label_mu = AB::Expr::from_u16(MR_UPDATE_NEW_LABEL as u16 + 16);
let label_hout = AB::Expr::from_u16(RETURN_HASH_LABEL as u16 + 32);
let label_sout = AB::Expr::from_u16(RETURN_STATE_LABEL as u16 + 32);
let label_abp = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 32);
let v_bp = compute_hasher_message::<AB>(
challenges,
label_bp,
addr_next.clone(),
node_index.clone(),
&state,
);
let v_sout = compute_hasher_message::<AB>(
challenges,
label_sout,
addr_next.clone(),
node_index.clone(),
&state,
);
let two = AB::Expr::from_u16(2);
let bit = node_index.clone() - two * node_index_next.clone();
let leaf_word: [AB::Expr; 4] = [
(one.clone() - bit.clone()) * state[0].clone() + bit.clone() * state[4].clone(),
(one.clone() - bit.clone()) * state[1].clone() + bit.clone() * state[5].clone(),
(one.clone() - bit.clone()) * state[2].clone() + bit.clone() * state[6].clone(),
(one.clone() - bit.clone()) * state[3].clone() + bit.clone() * state[7].clone(),
];
let v_mp = compute_hasher_word_message::<AB>(
challenges,
label_mp,
addr_next.clone(),
node_index.clone(),
&leaf_word,
);
let v_mv = compute_hasher_word_message::<AB>(
challenges,
label_mv,
addr_next.clone(),
node_index.clone(),
&leaf_word,
);
let v_mu = compute_hasher_word_message::<AB>(
challenges,
label_mu,
addr_next.clone(),
node_index.clone(),
&leaf_word,
);
let result_word: [AB::Expr; 4] =
[state[0].clone(), state[1].clone(), state[2].clone(), state[3].clone()];
let v_hout = compute_hasher_word_message::<AB>(
challenges,
label_hout,
addr_next.clone(),
node_index.clone(),
&result_word,
);
let rate_next: [AB::Expr; 8] = [
state_next[0].clone(),
state_next[1].clone(),
state_next[2].clone(),
state_next[3].clone(),
state_next[4].clone(),
state_next[5].clone(),
state_next[6].clone(),
state_next[7].clone(),
];
let v_abp = compute_hasher_rate_message::<AB>(
challenges,
label_abp,
addr_next.clone(),
node_index.clone(),
&rate_next,
);
let flag_sum = f_bp.clone()
+ f_mp.clone()
+ f_mv.clone()
+ f_mu.clone()
+ f_hout.clone()
+ f_sout.clone()
+ f_abp.clone();
let sum = v_bp * f_bp
+ v_mp * f_mp
+ v_mv * f_mv
+ v_mu * f_mu
+ v_hout * f_hout
+ v_sout * f_sout
+ v_abp * f_abp;
HasherResponse { sum, flag_sum }
}
fn compute_hperm_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
use crate::trace::decoder::USER_OP_HELPERS_OFFSET;
let addr: AB::Expr = local.decoder[USER_OP_HELPERS_OFFSET].clone().into();
let input_state: [AB::Expr; 12] = core::array::from_fn(|i| local.stack[i].clone().into());
let output_state: [AB::Expr; 12] = core::array::from_fn(|i| next.stack[i].clone().into());
let input_label: AB::Expr = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 16);
let node_index_zero: AB::Expr = AB::Expr::ZERO;
let input_msg = compute_hasher_message::<AB>(
challenges,
input_label,
addr.clone(),
node_index_zero.clone(),
&input_state,
);
let output_label: AB::Expr = AB::Expr::from_u16(RETURN_STATE_LABEL as u16 + 32);
let addr_offset: AB::Expr = AB::Expr::from_u16((HASH_CYCLE_LEN - 1) as u16);
let addr_next = addr + addr_offset;
let output_msg = compute_hasher_message::<AB>(
challenges,
output_label,
addr_next,
node_index_zero,
&output_state,
);
input_msg * output_msg
}
fn compute_log_precompile_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let helper_base = USER_OP_HELPERS_OFFSET;
let addr: AB::Expr = local.decoder[helper_base + HELPER_ADDR_IDX].clone().into();
let cap_prev: [AB::Expr; 4] = core::array::from_fn(|i| {
local.decoder[helper_base + HELPER_CAP_PREV_RANGE.start + i].clone().into()
});
let comm: [AB::Expr; 4] =
core::array::from_fn(|i| local.stack[STACK_COMM_RANGE.start + i].clone().into());
let tag: [AB::Expr; 4] =
core::array::from_fn(|i| local.stack[STACK_TAG_RANGE.start + i].clone().into());
let state_input: [AB::Expr; 12] = [
comm[0].clone(),
comm[1].clone(),
comm[2].clone(),
comm[3].clone(),
tag[0].clone(),
tag[1].clone(),
tag[2].clone(),
tag[3].clone(),
cap_prev[0].clone(),
cap_prev[1].clone(),
cap_prev[2].clone(),
cap_prev[3].clone(),
];
let r0: [AB::Expr; 4] =
core::array::from_fn(|i| next.stack[STACK_R0_RANGE.start + i].clone().into());
let r1: [AB::Expr; 4] =
core::array::from_fn(|i| next.stack[STACK_R1_RANGE.start + i].clone().into());
let cap_next: [AB::Expr; 4] =
core::array::from_fn(|i| next.stack[STACK_CAP_NEXT_RANGE.start + i].clone().into());
let state_output: [AB::Expr; 12] = [
r0[0].clone(),
r0[1].clone(),
r0[2].clone(),
r0[3].clone(),
r1[0].clone(),
r1[1].clone(),
r1[2].clone(),
r1[3].clone(),
cap_next[0].clone(),
cap_next[1].clone(),
cap_next[2].clone(),
cap_next[3].clone(),
];
let input_label: AB::Expr = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 16);
let input_msg = compute_hasher_message::<AB>(
challenges,
input_label,
addr.clone(),
AB::Expr::ZERO,
&state_input,
);
let output_label: AB::Expr = AB::Expr::from_u16(RETURN_STATE_LABEL as u16 + 32);
let addr_offset: AB::Expr = AB::Expr::from_u16((HASH_CYCLE_LEN - 1) as u16);
let output_msg = compute_hasher_message::<AB>(
challenges,
output_label,
addr + addr_offset,
AB::Expr::ZERO,
&state_output,
);
input_msg * output_msg
}
fn compute_hasher_message<AB: LiftedAirBuilder<F = Felt>>(
challenges: &Challenges<AB::ExprEF>,
transition_label: AB::Expr,
addr: AB::Expr,
node_index: AB::Expr,
state: &[AB::Expr; 12],
) -> AB::ExprEF {
challenges.encode([
transition_label,
addr,
node_index,
state[0].clone(),
state[1].clone(),
state[2].clone(),
state[3].clone(),
state[4].clone(),
state[5].clone(),
state[6].clone(),
state[7].clone(),
state[8].clone(),
state[9].clone(),
state[10].clone(),
state[11].clone(),
])
}
fn compute_hasher_word_message<AB: LiftedAirBuilder<F = Felt>>(
challenges: &Challenges<AB::ExprEF>,
transition_label: AB::Expr,
addr: AB::Expr,
node_index: AB::Expr,
word: &[AB::Expr; 4],
) -> AB::ExprEF {
challenges.encode([
transition_label,
addr,
node_index,
word[0].clone(),
word[1].clone(),
word[2].clone(),
word[3].clone(),
])
}
fn compute_hasher_rate_message<AB: LiftedAirBuilder<F = Felt>>(
challenges: &Challenges<AB::ExprEF>,
transition_label: AB::Expr,
addr: AB::Expr,
node_index: AB::Expr,
rate: &[AB::Expr; 8],
) -> AB::ExprEF {
challenges.encode([
transition_label,
addr,
node_index,
rate[0].clone(),
rate[1].clone(),
rate[2].clone(),
rate[3].clone(),
rate[4].clone(),
rate[5].clone(),
rate[6].clone(),
rate[7].clone(),
])
}
fn compute_ace_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let label: AB::Expr = AB::Expr::from(ACE_INIT_LABEL);
let ctx: AB::Expr = local.ctx.clone().into();
let clk: AB::Expr = local.clk.clone().into();
let ptr: AB::Expr = local.stack[0].clone().into();
let num_read_rows: AB::Expr = local.stack[1].clone().into();
let num_eval_rows: AB::Expr = local.stack[2].clone().into();
challenges.encode([label, clk, ctx, ptr, num_read_rows, num_eval_rows])
}
fn compute_ace_response<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let label: AB::Expr = AB::Expr::from(ACE_INIT_LABEL);
let clk: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + CLK_IDX].clone().into();
let ctx: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + CTX_IDX].clone().into();
let ptr: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + PTR_IDX].clone().into();
let read_num_eval: AB::Expr =
local.chiplets[NUM_ACE_SELECTORS + READ_NUM_EVAL_IDX].clone().into();
let num_eval_rows: AB::Expr = read_num_eval + AB::Expr::ONE;
let id_0: AB::Expr = local.chiplets[NUM_ACE_SELECTORS + ID_0_IDX].clone().into();
let num_read_rows: AB::Expr = id_0 + AB::Expr::ONE - num_eval_rows.clone();
challenges.encode([label, clk, ctx, ptr, num_read_rows, num_eval_rows])
}
fn compute_kernel_rom_response<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let s_first: AB::Expr = local.chiplets[NUM_KERNEL_ROM_SELECTORS].clone().into();
let init_label: AB::Expr = AB::Expr::from(KERNEL_PROC_INIT_LABEL);
let call_label: AB::Expr = AB::Expr::from(KERNEL_PROC_CALL_LABEL);
let label: AB::Expr = s_first.clone() * init_label + (AB::Expr::ONE - s_first) * call_label;
let root0: AB::Expr = local.chiplets[NUM_KERNEL_ROM_SELECTORS + 1].clone().into();
let root1: AB::Expr = local.chiplets[NUM_KERNEL_ROM_SELECTORS + 2].clone().into();
let root2: AB::Expr = local.chiplets[NUM_KERNEL_ROM_SELECTORS + 3].clone().into();
let root3: AB::Expr = local.chiplets[NUM_KERNEL_ROM_SELECTORS + 4].clone().into();
challenges.encode([label, root0, root1, root2, root3])
}
#[derive(Clone, Copy)]
enum ControlBlockOp {
Join,
Split,
Loop,
Call,
Syscall,
}
impl ControlBlockOp {
fn opcode(&self) -> u8 {
match self {
ControlBlockOp::Join => opcodes::JOIN,
ControlBlockOp::Split => opcodes::SPLIT,
ControlBlockOp::Loop => opcodes::LOOP,
ControlBlockOp::Call => opcodes::CALL,
ControlBlockOp::Syscall => opcodes::SYSCALL,
}
}
}
fn compute_control_block_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
op: ControlBlockOp,
) -> AB::ExprEF {
let transition_label: AB::Expr = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 16);
let addr_next: AB::Expr = next.decoder[ADDR_COL_IDX].clone().into();
let hasher_state: [AB::Expr; 8] =
core::array::from_fn(|i| local.decoder[HASHER_STATE_RANGE.start + i].clone().into());
let op_code: AB::Expr = AB::Expr::from_u16(op.opcode() as u16);
let state: [AB::Expr; 12] = [
hasher_state[0].clone(),
hasher_state[1].clone(),
hasher_state[2].clone(),
hasher_state[3].clone(),
hasher_state[4].clone(),
hasher_state[5].clone(),
hasher_state[6].clone(),
hasher_state[7].clone(),
AB::Expr::ZERO,
op_code, AB::Expr::ZERO,
AB::Expr::ZERO,
];
compute_hasher_message::<AB>(challenges, transition_label, addr_next, AB::Expr::ZERO, &state)
}
fn compute_call_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let control_req =
compute_control_block_request::<AB>(local, next, challenges, ControlBlockOp::Call);
let fmp_req = compute_fmp_write_request::<AB>(local, next, challenges);
control_req * fmp_req
}
fn compute_dyn_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let control_req =
compute_control_block_request_zeros::<AB>(local, next, challenges, opcodes::DYN);
let callee_hash_req = compute_dyn_callee_hash_read::<AB>(local, challenges);
control_req * callee_hash_req
}
fn compute_dyncall_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let control_req =
compute_control_block_request_zeros::<AB>(local, next, challenges, opcodes::DYNCALL);
let callee_hash_req = compute_dyn_callee_hash_read::<AB>(local, challenges);
let fmp_req = compute_fmp_write_request::<AB>(local, next, challenges);
control_req * callee_hash_req * fmp_req
}
fn compute_syscall_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let control_req =
compute_control_block_request::<AB>(local, next, challenges, ControlBlockOp::Syscall);
let root0: AB::Expr = local.decoder[HASHER_STATE_RANGE.start].clone().into();
let root1: AB::Expr = local.decoder[HASHER_STATE_RANGE.start + 1].clone().into();
let root2: AB::Expr = local.decoder[HASHER_STATE_RANGE.start + 2].clone().into();
let root3: AB::Expr = local.decoder[HASHER_STATE_RANGE.start + 3].clone().into();
let label: AB::Expr = AB::Expr::from(KERNEL_PROC_CALL_LABEL);
let kernel_req = challenges.encode([label, root0, root1, root2, root3]);
control_req * kernel_req
}
fn compute_span_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let transition_label: AB::Expr = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 16);
let addr_next: AB::Expr = next.decoder[ADDR_COL_IDX].clone().into();
let hasher_state: [AB::Expr; 8] =
core::array::from_fn(|i| local.decoder[HASHER_STATE_RANGE.start + i].clone().into());
let state: [AB::Expr; 12] = [
hasher_state[0].clone(),
hasher_state[1].clone(),
hasher_state[2].clone(),
hasher_state[3].clone(),
hasher_state[4].clone(),
hasher_state[5].clone(),
hasher_state[6].clone(),
hasher_state[7].clone(),
AB::Expr::ZERO,
AB::Expr::ZERO,
AB::Expr::ZERO,
AB::Expr::ZERO,
];
compute_hasher_message::<AB>(challenges, transition_label, addr_next, AB::Expr::ZERO, &state)
}
fn compute_respan_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let transition_label: AB::Expr = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 32);
let addr_next: AB::Expr = next.decoder[ADDR_COL_IDX].clone().into();
let addr_for_msg = addr_next - AB::Expr::ONE;
let hasher_state: [AB::Expr; 8] =
core::array::from_fn(|i| local.decoder[HASHER_STATE_RANGE.start + i].clone().into());
compute_hasher_rate_message::<AB>(
challenges,
transition_label,
addr_for_msg,
AB::Expr::ZERO,
&hasher_state,
)
}
fn compute_end_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let transition_label: AB::Expr = AB::Expr::from_u16(RETURN_HASH_LABEL as u16 + 32);
let addr: AB::Expr = local.decoder[ADDR_COL_IDX].clone().into()
+ AB::Expr::from_u16((HASH_CYCLE_LEN - 1) as u16);
let digest: [AB::Expr; 4] =
core::array::from_fn(|i| local.decoder[HASHER_STATE_RANGE.start + i].clone().into());
compute_hasher_word_message::<AB>(challenges, transition_label, addr, AB::Expr::ZERO, &digest)
}
fn compute_control_block_request_zeros<AB: LiftedAirBuilder<F = Felt>>(
_local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
opcode: u8,
) -> AB::ExprEF {
let transition_label: AB::Expr = AB::Expr::from_u16(LINEAR_HASH_LABEL as u16 + 16);
let addr_next: AB::Expr = next.decoder[ADDR_COL_IDX].clone().into();
let op_code: AB::Expr = AB::Expr::from_u16(opcode as u16);
let state: [AB::Expr; 12] = [
AB::Expr::ZERO,
AB::Expr::ZERO,
AB::Expr::ZERO,
AB::Expr::ZERO,
AB::Expr::ZERO,
AB::Expr::ZERO,
AB::Expr::ZERO,
AB::Expr::ZERO,
AB::Expr::ZERO,
op_code, AB::Expr::ZERO,
AB::Expr::ZERO,
];
compute_hasher_message::<AB>(challenges, transition_label, addr_next, AB::Expr::ZERO, &state)
}
fn compute_fmp_write_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let label: AB::Expr = AB::Expr::from_u16(MEMORY_WRITE_ELEMENT_LABEL as u16);
let ctx: AB::Expr = next.ctx.clone().into();
let clk: AB::Expr = local.clk.clone().into();
let addr: AB::Expr = AB::Expr::from(FMP_ADDR);
let element: AB::Expr = AB::Expr::from(FMP_INIT_VALUE);
challenges.encode([label, ctx, addr, clk, element])
}
fn compute_dyn_callee_hash_read<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
let label: AB::Expr = AB::Expr::from_u16(MEMORY_READ_WORD_LABEL as u16);
let ctx: AB::Expr = local.ctx.clone().into();
let clk: AB::Expr = local.clk.clone().into();
let addr: AB::Expr = local.stack[0].clone().into();
let w0: AB::Expr = local.decoder[HASHER_STATE_RANGE.start].clone().into();
let w1: AB::Expr = local.decoder[HASHER_STATE_RANGE.start + 1].clone().into();
let w2: AB::Expr = local.decoder[HASHER_STATE_RANGE.start + 2].clone().into();
let w3: AB::Expr = local.decoder[HASHER_STATE_RANGE.start + 3].clone().into();
challenges.encode([label, ctx, addr, clk, w0, w1, w2, w3])
}
fn compute_mpverify_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
use crate::trace::decoder::USER_OP_HELPERS_OFFSET;
let helper_0: AB::Expr = local.decoder[USER_OP_HELPERS_OFFSET].clone().into();
let merkle_cycle_len: AB::Expr = AB::Expr::from_u16(HASH_CYCLE_LEN as u16);
let node_value: [AB::Expr; 4] = core::array::from_fn(|i| local.stack[i].clone().into());
let node_depth: AB::Expr = local.stack[4].clone().into();
let node_index: AB::Expr = local.stack[5].clone().into();
let root: [AB::Expr; 4] = core::array::from_fn(|i| local.stack[6 + i].clone().into());
let input_label: AB::Expr = AB::Expr::from_u16(MP_VERIFY_LABEL as u16 + 16);
let input_msg = compute_hasher_word_message::<AB>(
challenges,
input_label,
helper_0.clone(),
node_index.clone(),
&node_value,
);
let output_addr = helper_0 + node_depth * merkle_cycle_len - AB::Expr::ONE;
let output_label: AB::Expr = AB::Expr::from_u16(RETURN_HASH_LABEL as u16 + 32);
let output_msg = compute_hasher_word_message::<AB>(
challenges,
output_label,
output_addr,
AB::Expr::ZERO,
&root,
);
input_msg * output_msg
}
fn compute_mrupdate_request<AB: LiftedAirBuilder<F = Felt>>(
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
challenges: &Challenges<AB::ExprEF>,
) -> AB::ExprEF {
use crate::trace::decoder::USER_OP_HELPERS_OFFSET;
let helper_0: AB::Expr = local.decoder[USER_OP_HELPERS_OFFSET].clone().into();
let merkle_cycle_len: AB::Expr = AB::Expr::from_u16(HASH_CYCLE_LEN as u16);
let two_merkle_cycles: AB::Expr = merkle_cycle_len.clone() + merkle_cycle_len.clone();
let old_node: [AB::Expr; 4] = core::array::from_fn(|i| local.stack[i].clone().into());
let depth: AB::Expr = local.stack[4].clone().into();
let index: AB::Expr = local.stack[5].clone().into();
let old_root: [AB::Expr; 4] = core::array::from_fn(|i| local.stack[6 + i].clone().into());
let new_node: [AB::Expr; 4] = core::array::from_fn(|i| local.stack[10 + i].clone().into());
let new_root: [AB::Expr; 4] = core::array::from_fn(|i| next.stack[i].clone().into());
let input_old_label: AB::Expr = AB::Expr::from_u16(MR_UPDATE_OLD_LABEL as u16 + 16);
let input_old_msg = compute_hasher_word_message::<AB>(
challenges,
input_old_label,
helper_0.clone(),
index.clone(),
&old_node,
);
let output_old_addr =
helper_0.clone() + depth.clone() * merkle_cycle_len.clone() - AB::Expr::ONE;
let output_old_label: AB::Expr = AB::Expr::from_u16(RETURN_HASH_LABEL as u16 + 32);
let output_old_msg = compute_hasher_word_message::<AB>(
challenges,
output_old_label.clone(),
output_old_addr,
AB::Expr::ZERO,
&old_root,
);
let input_new_addr = helper_0.clone() + depth.clone() * merkle_cycle_len.clone();
let input_new_label: AB::Expr = AB::Expr::from_u16(MR_UPDATE_NEW_LABEL as u16 + 16);
let input_new_msg = compute_hasher_word_message::<AB>(
challenges,
input_new_label,
input_new_addr,
index,
&new_node,
);
let output_new_addr = helper_0 + depth * two_merkle_cycles - AB::Expr::ONE;
let output_new_msg = compute_hasher_word_message::<AB>(
challenges,
output_old_label,
output_new_addr,
AB::Expr::ZERO,
&new_root,
);
input_old_msg * output_old_msg * input_new_msg * output_new_msg
}
#[cfg(test)]
mod tests {
use crate::{
Felt,
trace::chiplets::{
ace::ACE_INIT_LABEL,
bitwise::{BITWISE_AND_LABEL, BITWISE_XOR_LABEL},
kernel_rom::{KERNEL_PROC_CALL_LABEL, KERNEL_PROC_INIT_LABEL},
memory::{
MEMORY_READ_ELEMENT_LABEL, MEMORY_READ_WORD_LABEL, MEMORY_WRITE_ELEMENT_LABEL,
MEMORY_WRITE_WORD_LABEL,
},
},
};
#[test]
fn test_operation_labels() {
assert_eq!(BITWISE_AND_LABEL, Felt::new(2));
assert_eq!(BITWISE_XOR_LABEL, Felt::new(6));
assert_eq!(MEMORY_WRITE_ELEMENT_LABEL, 4);
assert_eq!(MEMORY_READ_ELEMENT_LABEL, 12);
assert_eq!(MEMORY_WRITE_WORD_LABEL, 20);
assert_eq!(MEMORY_READ_WORD_LABEL, 28);
}
#[test]
fn test_memory_label_formula() {
fn label(is_read: u64, is_word: u64) -> u64 {
4 + 8 * is_read + 16 * is_word
}
assert_eq!(label(0, 0), MEMORY_WRITE_ELEMENT_LABEL as u64); assert_eq!(label(1, 0), MEMORY_READ_ELEMENT_LABEL as u64); assert_eq!(label(0, 1), MEMORY_WRITE_WORD_LABEL as u64); assert_eq!(label(1, 1), MEMORY_READ_WORD_LABEL as u64); }
#[test]
fn test_ace_label() {
assert_eq!(ACE_INIT_LABEL, Felt::new(8));
}
#[test]
fn test_kernel_rom_labels() {
assert_eq!(KERNEL_PROC_CALL_LABEL, Felt::new(16));
assert_eq!(KERNEL_PROC_INIT_LABEL, Felt::new(48));
}
}