use core::array;
use miden_core::field::PrimeCharacteristicRing;
use crate::{
constraints::lookup::{
main_air::{MainBusContext, MainLookupBuilder},
messages::{BlockStackMsg, LogCapacityMsg, RangeMsg},
},
lookup::{Deg, LookupBatch, LookupColumn, LookupGroup},
trace::log_precompile::{HELPER_CAP_PREV_RANGE, STACK_CAP_NEXT_RANGE},
};
pub(in crate::constraints::lookup) const MAX_INTERACTIONS_PER_ROW: usize = 5;
#[allow(clippy::too_many_lines)]
pub(in crate::constraints::lookup) fn emit_block_stack_and_range_logcap<LB>(
builder: &mut LB,
ctx: &MainBusContext<LB>,
) where
LB: MainLookupBuilder,
{
let local = ctx.local;
let next = ctx.next;
let op_flags = &ctx.op_flags;
let dec = &local.decoder;
let dec_next = &next.decoder;
let stk = &local.stack;
let stk_next = &next.stack;
let addr = dec.addr;
let addr_next = dec_next.addr;
let h4 = dec.hasher_state[4];
let h5 = dec.hasher_state[5];
let h1_next = dec_next.hasher_state[1];
let end_flags = dec.end_block_flags();
let s0 = stk.get(0);
let b0 = stk.b0;
let b1 = stk.b1;
let b0_next = stk_next.b0;
let b1_next = stk_next.b1;
let sys_ctx = local.system.ctx;
let sys_ctx_next = next.system.ctx;
let fn_hash = local.system.fn_hash;
let fn_hash_next = next.system.fn_hash;
let range_m = local.range.multiplicity;
let range_v = local.range.value;
let user_helpers = dec.user_op_helpers();
let f_u32rc = op_flags.u32_rc_op();
let f_log_precompile = op_flags.log_precompile();
let u32rc_helpers: [LB::Var; 4] = array::from_fn(|i| user_helpers[i]);
let cap_prev: [LB::Var; 4] = array::from_fn(|i| user_helpers[HELPER_CAP_PREV_RANGE.start + i]);
let cap_next: [LB::Var; 4] = array::from_fn(|i| stk_next.get(STACK_CAP_NEXT_RANGE.start + i));
builder.next_column(
|col| {
col.group(
"main_interactions",
|g| {
let f =
op_flags.join() + op_flags.split() + op_flags.span() + op_flags.dyn_op();
g.add(
"join_split_span_dyn",
f,
|| {
let block_id = addr_next.into();
let parent_id = addr.into();
let is_loop = LB::Expr::ZERO;
BlockStackMsg::Simple { block_id, parent_id, is_loop }
},
Deg { v: 5, u: 6 },
);
g.add(
"loop",
op_flags.loop_op(),
|| {
let block_id = addr_next.into();
let parent_id = addr.into();
let is_loop = s0.into();
BlockStackMsg::Simple { block_id, parent_id, is_loop }
},
Deg { v: 5, u: 6 },
);
g.add(
"dyncall",
op_flags.dyncall(),
|| {
let block_id = addr_next.into();
let parent_id = addr.into();
let is_loop = LB::Expr::ZERO;
let ctx = sys_ctx.into();
let fmp = h4.into();
let depth = h5.into();
let fn_hash = fn_hash.map(LB::Expr::from);
BlockStackMsg::Full {
block_id,
parent_id,
is_loop,
ctx,
fmp,
depth,
fn_hash,
}
},
Deg { v: 5, u: 6 },
);
let f = op_flags.call() + op_flags.syscall();
g.add(
"call_syscall",
f,
|| {
let block_id = addr_next.into();
let parent_id = addr.into();
let is_loop = LB::Expr::ZERO;
let ctx = sys_ctx.into();
let fmp = b0.into();
let depth = b1.into();
let fn_hash = fn_hash.map(LB::Expr::from);
BlockStackMsg::Full {
block_id,
parent_id,
is_loop,
ctx,
fmp,
depth,
fn_hash,
}
},
Deg { v: 4, u: 5 },
);
let f = op_flags.end()
* (LB::Expr::ONE - end_flags.is_call.into() - end_flags.is_syscall.into());
g.remove(
"end_simple",
f,
|| {
let block_id = addr.into();
let parent_id = addr_next.into();
let is_loop = end_flags.is_loop.into();
BlockStackMsg::Simple { block_id, parent_id, is_loop }
},
Deg { v: 5, u: 6 },
);
let f =
op_flags.end() * (end_flags.is_call.into() + end_flags.is_syscall.into());
g.remove(
"end_call_syscall",
f,
|| {
let block_id = addr.into();
let parent_id = addr_next.into();
let is_loop = end_flags.is_loop.into();
let ctx = sys_ctx_next.into();
let fmp = b0_next.into();
let depth = b1_next.into();
let fn_hash = fn_hash_next.map(LB::Expr::from);
BlockStackMsg::Full {
block_id,
parent_id,
is_loop,
ctx,
fmp,
depth,
fn_hash,
}
},
Deg { v: 5, u: 6 },
);
g.batch(
"respan",
op_flags.respan(),
|b| {
let block_id_add = addr_next.into();
let parent_id_add = h1_next.into();
let is_loop_add = LB::Expr::ZERO;
b.add(
"respan_add",
BlockStackMsg::Simple {
block_id: block_id_add,
parent_id: parent_id_add,
is_loop: is_loop_add,
},
Deg { v: 4, u: 5 },
);
let block_id_rem = addr.into();
let parent_id_rem = h1_next.into();
let is_loop_rem = LB::Expr::ZERO;
b.remove(
"respan_remove",
BlockStackMsg::Simple {
block_id: block_id_rem,
parent_id: parent_id_rem,
is_loop: is_loop_rem,
},
Deg { v: 4, u: 5 },
);
},
Deg { v: 5, u: 6 }, );
g.batch(
"u32_range_check",
f_u32rc,
move |b| {
for helper in u32rc_helpers {
let value = helper.into();
b.remove("u32rc_remove", RangeMsg { value }, Deg { v: 3, u: 4 });
}
},
Deg { v: 6, u: 7 }, );
g.batch(
"log_precompile_capacity",
f_log_precompile,
move |b| {
let capacity_prev = cap_prev.map(LB::Expr::from);
b.remove(
"logpre_cap_remove",
LogCapacityMsg { capacity: capacity_prev },
Deg { v: 5, u: 6 },
);
let capacity_next = cap_next.map(LB::Expr::from);
b.add(
"logpre_cap_add",
LogCapacityMsg { capacity: capacity_next },
Deg { v: 5, u: 6 },
);
},
Deg { v: 6, u: 7 }, );
},
Deg { v: 6, u: 7 },
);
col.group(
"range_table",
|g| {
g.insert(
"range_response",
LB::Expr::ONE,
range_m.into(),
|| {
let value = range_v.into();
RangeMsg { value }
},
Deg { v: 1, u: 1 },
);
},
Deg { v: 1, u: 1 },
);
},
Deg { v: 8, u: 8 },
);
}