use core::array;
use miden_core::field::PrimeCharacteristicRing;
use crate::{
constraints::{
lookup::{
chiplet_air::{ChipletBusContext, ChipletLookupBuilder},
messages::{MemoryMsg, RangeMsg, SiblingFromRatesMsg},
},
utils::BoolNot,
},
lookup::{Deg, LookupBatch, LookupColumn, LookupGroup},
trace::chiplets::ace::{ACE_INSTRUCTION_ID1_OFFSET, ACE_INSTRUCTION_ID2_OFFSET},
};
pub(in crate::constraints::lookup) const MAX_INTERACTIONS_PER_ROW: usize = 5;
pub(in crate::constraints::lookup) fn emit_hash_kernel_table<LB>(
builder: &mut LB,
ctx: &ChipletBusContext<LB>,
) where
LB: ChipletLookupBuilder,
{
let local = ctx.local;
let next = ctx.next;
let ctrl = local.controller();
let ctrl_next = next.controller();
let controller_flag = ctx.chiplet_active.controller.clone();
let hs0: LB::Expr = ctrl.s0.into();
let hs1: LB::Expr = ctrl.s1.into();
let hs2: LB::Expr = ctrl.s2.into();
let is_boundary: LB::Expr = ctrl.is_boundary.into();
let later_level = is_boundary.not();
let f_update_all = controller_flag.clone() * hs0.clone() * hs1.clone();
let f_update_later_levels = f_update_all * later_level;
let f_update_level0 = controller_flag.clone() * hs0.clone() * hs1.clone() * is_boundary.clone();
let f_mp_level0 = controller_flag * hs0 * hs1.not() * hs2.clone() * is_boundary;
let update_multiplicity = LB::Expr::ONE - hs2.double();
let rate_0: [LB::Var; 4] = array::from_fn(|i| ctrl.state[i]);
let rate_1: [LB::Var; 4] = array::from_fn(|i| ctrl.state[4 + i]);
let mrupdate_id = ctrl.mrupdate_id;
let node_index = ctrl.node_index;
let slack_3 = ctrl.capacity()[3];
let node_index_next: LB::Expr = ctrl_next.node_index.into();
let bit: LB::Expr = node_index.into() - node_index_next.double();
let ace = local.ace();
let block_sel: LB::Expr = ace.s_block.into();
let is_ace_row = ctx.chiplet_active.ace.clone();
let f_ace_read: LB::Expr = is_ace_row.clone() * block_sel.not();
let f_ace_eval: LB::Expr = is_ace_row * block_sel;
let ace_clk = ace.clk;
let ace_ctx = ace.ctx;
let ace_ptr = ace.ptr;
let ace_v0 = ace.v_0;
let ace_v1 = ace.v_1;
let ace_id_1 = ace.id_1;
let ace_id_2 = ace.eval().id_2;
let ace_eval_op = ace.eval_op;
let mem_active = ctx.chiplet_active.memory.clone();
let mem = local.memory();
let mem_d0 = mem.d0;
let mem_d1 = mem.d1;
let mem_w0 = local.memory_word_addr_lo();
let mem_w1 = local.memory_word_addr_hi();
builder.next_column(
|col| {
col.group(
"sibling_ace_memory",
|g| {
let later_level_bit = bit.clone();
g.insert(
"sibling_update",
f_update_later_levels,
update_multiplicity.clone(),
move || SiblingFromRatesMsg {
direction_bit: later_level_bit,
mrupdate_id: mrupdate_id.into(),
node_index: node_index.into(),
rate_0: rate_0.map(Into::into),
rate_1: rate_1.map(Into::into),
},
Deg { v: 5, u: 6 },
);
g.batch(
"sibling_update_level0",
f_update_level0,
move |b| {
b.insert(
"sibling_update",
update_multiplicity,
SiblingFromRatesMsg {
direction_bit: bit,
mrupdate_id: mrupdate_id.into(),
node_index: node_index.into(),
rate_0: rate_0.map(Into::into),
rate_1: rate_1.map(Into::into),
},
Deg { v: 5, u: 6 },
);
let slack_3: LB::Expr = slack_3.into();
b.remove(
"merkle_index_slack_3",
RangeMsg { value: slack_3.clone() },
Deg { v: 4, u: 5 },
);
b.remove(
"merkle_index_slack_3_double",
RangeMsg { value: slack_3.double() },
Deg { v: 4, u: 5 },
);
},
Deg { v: 7, u: 8 },
);
g.batch(
"mpverify_level0_index_range",
f_mp_level0,
move |b| {
let slack_3: LB::Expr = slack_3.into();
b.remove(
"merkle_index_slack_3",
RangeMsg { value: slack_3.clone() },
Deg { v: 5, u: 6 },
);
b.remove(
"merkle_index_slack_3_double",
RangeMsg { value: slack_3.double() },
Deg { v: 5, u: 6 },
);
},
Deg { v: 6, u: 7 },
);
g.remove(
"ace_mem_read_word",
f_ace_read,
move || {
let clk = ace_clk.into();
let ctx = ace_ctx.into();
let addr = ace_ptr.into();
let word = [
ace_v0.0.into(),
ace_v0.1.into(),
ace_v1.0.into(),
ace_v1.1.into(),
];
MemoryMsg::read_word(ctx, addr, clk, word)
},
Deg { v: 5, u: 6 },
);
g.remove(
"ace_mem_eval_element",
f_ace_eval,
move || {
let clk = ace_clk.into();
let ctx = ace_ctx.into();
let addr = ace_ptr.into();
let id_1: LB::Expr = ace_id_1.into();
let id_2: LB::Expr = ace_id_2.into();
let eval_op: LB::Expr = ace_eval_op.into();
let id_2_slot = id_2 * LB::Expr::from(ACE_INSTRUCTION_ID1_OFFSET);
let eval_op_slot = (eval_op + LB::Expr::ONE)
* LB::Expr::from(ACE_INSTRUCTION_ID2_OFFSET);
let element = id_1 + id_2_slot + eval_op_slot;
MemoryMsg::read_element(ctx, addr, clk, element)
},
Deg { v: 5, u: 6 },
);
g.batch(
"memory_range_checks",
mem_active,
move |b| {
b.remove(
"mem_d0",
RangeMsg { value: mem_d0.into() },
Deg { v: 3, u: 4 },
);
b.remove(
"mem_d1",
RangeMsg { value: mem_d1.into() },
Deg { v: 3, u: 4 },
);
let w0: LB::Expr = mem_w0.into();
let w1: LB::Expr = mem_w1.into();
let w1_mul4 = w1.clone() * LB::Expr::from_u16(4);
b.remove("mem_w0", RangeMsg { value: w0 }, Deg { v: 3, u: 4 });
b.remove("mem_w1", RangeMsg { value: w1 }, Deg { v: 3, u: 4 });
b.remove(
"mem_w1_mul4",
RangeMsg { value: w1_mul4 },
Deg { v: 3, u: 4 },
);
},
Deg { v: 7, u: 8 }, );
},
Deg { v: 7, u: 8 },
);
},
Deg { v: 7, u: 8 },
);
}