use miden_core::field::PrimeCharacteristicRing;
use miden_crypto::stark::air::LiftedAirBuilder;
use crate::{
MainTraceRow,
constraints::{
op_flags::OpFlags,
tagging::{
TagGroup, TaggingAirBuilderExt, ids::TAG_STACK_ARITH_BASE, tagged_assert_zero,
tagged_assert_zero_integrity,
},
},
trace::decoder::USER_OP_HELPERS_OFFSET,
};
#[allow(dead_code)]
pub const NUM_CONSTRAINTS: usize = 42;
const STACK_ARITH_BASE_ID: usize = TAG_STACK_ARITH_BASE;
const STACK_ARITH_NAMES: [&str; NUM_CONSTRAINTS] = [
"stack.arith.add",
"stack.arith.neg",
"stack.arith.mul",
"stack.arith.inv",
"stack.arith.incr",
"stack.arith.not",
"stack.arith.not",
"stack.arith.and",
"stack.arith.and",
"stack.arith.and",
"stack.arith.or",
"stack.arith.or",
"stack.arith.or",
"stack.arith.eq",
"stack.arith.eq",
"stack.arith.eqz",
"stack.arith.eqz",
"stack.arith.expacc",
"stack.arith.expacc",
"stack.arith.expacc",
"stack.arith.expacc",
"stack.arith.expacc",
"stack.arith.ext2mul",
"stack.arith.ext2mul",
"stack.arith.ext2mul",
"stack.arith.ext2mul",
"stack.arith.u32.shared",
"stack.arith.u32.output",
"stack.arith.u32.output",
"stack.arith.u32.split",
"stack.arith.u32.add",
"stack.arith.u32.add3",
"stack.arith.u32.sub",
"stack.arith.u32.sub",
"stack.arith.u32.sub",
"stack.arith.u32.mul",
"stack.arith.u32.madd",
"stack.arith.u32.div",
"stack.arith.u32.div",
"stack.arith.u32.div",
"stack.arith.u32.assert2",
"stack.arith.u32.assert2",
];
const STACK_ARITH_TAGS: TagGroup = TagGroup {
base: STACK_ARITH_BASE_ID,
names: &STACK_ARITH_NAMES,
};
pub fn enforce_main<AB>(
builder: &mut AB,
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
op_flags: &OpFlags<AB::Expr>,
) where
AB: LiftedAirBuilder,
{
let mut idx = 0usize;
let s0: AB::Expr = local.stack[0].clone().into();
let s1: AB::Expr = local.stack[1].clone().into();
let s2: AB::Expr = local.stack[2].clone().into();
let s3: AB::Expr = local.stack[3].clone().into();
let s0_next: AB::Expr = next.stack[0].clone().into();
let s1_next: AB::Expr = next.stack[1].clone().into();
let s2_next: AB::Expr = next.stack[2].clone().into();
let s3_next: AB::Expr = next.stack[3].clone().into();
let base = USER_OP_HELPERS_OFFSET;
let uop_h0: AB::Expr = local.decoder[base].clone().into();
let uop_h1: AB::Expr = local.decoder[base + 1].clone().into();
let uop_h2: AB::Expr = local.decoder[base + 2].clone().into();
let uop_h3: AB::Expr = local.decoder[base + 3].clone().into();
let uop_h4: AB::Expr = local.decoder[base + 4].clone().into();
let is_add = op_flags.add();
let is_neg = op_flags.neg();
let is_mul = op_flags.mul();
let is_inv = op_flags.inv();
let is_incr = op_flags.incr();
let is_not = op_flags.not();
let is_and = op_flags.and();
let is_or = op_flags.or();
let is_eq = op_flags.eq();
let is_eqz = op_flags.eqz();
let is_expacc = op_flags.expacc();
let is_ext2mul = op_flags.ext2mul();
let is_u32add = op_flags.u32add();
let is_u32sub = op_flags.u32sub();
let is_u32mul = op_flags.u32mul();
let is_u32div = op_flags.u32div();
let is_u32split = op_flags.u32split();
let is_u32assert2 = op_flags.u32assert2();
let is_u32add3 = op_flags.u32add3();
let is_u32madd = op_flags.u32madd();
assert_zero(builder, &mut idx, is_add * (s0_next.clone() - (s0.clone() + s1.clone())));
assert_zero(builder, &mut idx, is_neg * (s0_next.clone() + s0.clone()));
assert_zero(builder, &mut idx, is_mul * (s0_next.clone() - s0.clone() * s1.clone()));
assert_zero(builder, &mut idx, is_inv * (s0_next.clone() * s0.clone() - AB::Expr::ONE));
assert_zero(builder, &mut idx, is_incr * (s0_next.clone() - s0.clone() - AB::Expr::ONE));
assert_zero_integrity(
builder,
&mut idx,
is_not.clone() * (s0.clone() * (s0.clone() - AB::Expr::ONE)),
);
assert_zero(builder, &mut idx, is_not * (s0.clone() + s0_next.clone() - AB::Expr::ONE));
assert_zero_integrity(
builder,
&mut idx,
is_and.clone() * (s0.clone() * (s0.clone() - AB::Expr::ONE)),
);
assert_zero_integrity(
builder,
&mut idx,
is_and.clone() * (s1.clone() * (s1.clone() - AB::Expr::ONE)),
);
assert_zero(builder, &mut idx, is_and * (s0_next.clone() - s0.clone() * s1.clone()));
assert_zero_integrity(
builder,
&mut idx,
is_or.clone() * (s0.clone() * (s0.clone() - AB::Expr::ONE)),
);
assert_zero_integrity(
builder,
&mut idx,
is_or.clone() * (s1.clone() * (s1.clone() - AB::Expr::ONE)),
);
assert_zero(
builder,
&mut idx,
is_or * (s0_next.clone() - (s0.clone() + s1.clone() - s0.clone() * s1.clone())),
);
let eq_diff = s0.clone() - s1.clone();
assert_zero(builder, &mut idx, is_eq.clone() * (eq_diff.clone() * s0_next.clone()));
assert_zero(
builder,
&mut idx,
is_eq * (s0_next.clone() - (AB::Expr::ONE - eq_diff * uop_h0.clone())),
);
assert_zero(builder, &mut idx, is_eqz.clone() * (s0.clone() * s0_next.clone()));
assert_zero(
builder,
&mut idx,
is_eqz * (s0_next.clone() - (AB::Expr::ONE - s0.clone() * uop_h0.clone())),
);
let exp = s1.clone();
let acc = s2.clone();
let exp_bit = s0_next.clone();
let exp_next = s1_next.clone();
let acc_next = s2_next.clone();
let exp_b = s3.clone();
let exp_b_next = s3_next.clone();
let exp_val = uop_h0.clone();
let two: AB::Expr = AB::Expr::from_u16(2);
assert_zero(builder, &mut idx, is_expacc.clone() * (exp_next - exp.clone() * exp.clone()));
assert_zero(
builder,
&mut idx,
is_expacc.clone()
* (exp_val.clone() - AB::Expr::ONE - (exp - AB::Expr::ONE) * exp_bit.clone()),
);
assert_zero(builder, &mut idx, is_expacc.clone() * (acc_next - acc * exp_val));
assert_zero(
builder,
&mut idx,
is_expacc.clone() * (exp_b - exp_b_next * two - exp_bit.clone()),
);
assert_zero(builder, &mut idx, is_expacc * (exp_bit.clone() * (exp_bit - AB::Expr::ONE)));
let ext_b0 = s0.clone();
let ext_b1 = s1.clone();
let ext_a0 = s2.clone();
let ext_a1 = s3.clone();
let ext_d0 = s0_next.clone();
let ext_d1 = s1_next.clone();
let ext_c0 = s2_next.clone();
let ext_c1 = s3_next.clone();
let ext_a0_b0 = ext_a0.clone() * ext_b0.clone();
let ext_a1_b1 = ext_a1.clone() * ext_b1.clone();
let seven: AB::Expr = AB::Expr::from_u16(7);
assert_zero(builder, &mut idx, is_ext2mul.clone() * (ext_d0 - ext_b0.clone()));
assert_zero(builder, &mut idx, is_ext2mul.clone() * (ext_d1 - ext_b1.clone()));
assert_zero(
builder,
&mut idx,
is_ext2mul.clone() * (ext_c0 - (ext_a0_b0.clone() + seven.clone() * ext_a1_b1.clone())),
);
assert_zero(
builder,
&mut idx,
is_ext2mul * (ext_c1 - ((ext_a0 + ext_a1) * (ext_b0 + ext_b1) - ext_a0_b0 - ext_a1_b1)),
);
let two_pow_16: AB::Expr = AB::Expr::from_u64(1u64 << 16);
let two_pow_32: AB::Expr = AB::Expr::from_u64(1u64 << 32);
let two_pow_48: AB::Expr = AB::Expr::from_u64(1u64 << 48);
let two_pow_32_minus_one: AB::Expr = AB::Expr::from_u64((1u64 << 32) - 1);
let u32_v_lo = uop_h1.clone() * two_pow_16.clone() + uop_h0.clone();
let u32_v_hi = uop_h3.clone() * two_pow_16 + uop_h2.clone();
let u32_v48 = uop_h2.clone() * two_pow_32.clone() + u32_v_lo.clone();
let u32_v64 = uop_h3.clone() * two_pow_48 + u32_v48.clone();
let u32_split_mul_madd = is_u32split.clone() + is_u32mul.clone() + is_u32madd.clone();
let u32_v_hi_comp = AB::Expr::ONE - uop_h4.clone() * (two_pow_32_minus_one - u32_v_hi.clone());
assert_zero_integrity(
builder,
&mut idx,
u32_split_mul_madd * (u32_v_hi_comp * u32_v_lo.clone()),
);
let u32_two_outputs = is_u32split.clone()
+ is_u32add.clone()
+ is_u32add3.clone()
+ is_u32mul.clone()
+ is_u32madd.clone();
assert_zero(
builder,
&mut idx,
u32_two_outputs.clone() * (s0_next.clone() - u32_v_lo.clone()),
);
assert_zero(builder, &mut idx, u32_two_outputs * (s1_next.clone() - u32_v_hi.clone()));
assert_zero_integrity(builder, &mut idx, is_u32split * (s0.clone() - u32_v64.clone()));
assert_zero_integrity(
builder,
&mut idx,
is_u32add * (s0.clone() + s1.clone() - u32_v48.clone()),
);
assert_zero_integrity(
builder,
&mut idx,
is_u32add3 * (s0.clone() + s1.clone() + s2.clone() - u32_v48.clone()),
);
assert_zero(
builder,
&mut idx,
is_u32sub.clone()
* (s1.clone() - (s0.clone() + s1_next.clone() - s0_next.clone() * two_pow_32.clone())),
);
assert_zero(
builder,
&mut idx,
is_u32sub.clone() * (s0_next.clone() * (s0_next.clone() - AB::Expr::ONE)),
);
assert_zero(builder, &mut idx, is_u32sub * (s1_next.clone() - u32_v_lo.clone()));
assert_zero_integrity(
builder,
&mut idx,
is_u32mul * (s0.clone() * s1.clone() - u32_v64.clone()),
);
assert_zero_integrity(
builder,
&mut idx,
is_u32madd * (s0.clone() * s1.clone() + s2 - u32_v64.clone()),
);
assert_zero(
builder,
&mut idx,
is_u32div.clone() * (s1.clone() - (s0.clone() * s1_next.clone() + s0_next.clone())),
);
assert_zero(
builder,
&mut idx,
is_u32div.clone() * (s1.clone() - s1_next.clone() - u32_v_lo.clone()),
);
assert_zero(
builder,
&mut idx,
is_u32div * (s0.clone() - s0_next.clone() - (u32_v_hi.clone() + AB::Expr::ONE)),
);
assert_zero(builder, &mut idx, is_u32assert2.clone() * (s0_next - u32_v_hi.clone()));
assert_zero(builder, &mut idx, is_u32assert2 * (s1_next - u32_v_lo));
}
fn assert_zero<AB: TaggingAirBuilderExt>(builder: &mut AB, idx: &mut usize, expr: AB::Expr) {
tagged_assert_zero(builder, &STACK_ARITH_TAGS, idx, expr);
}
fn assert_zero_integrity<AB: TaggingAirBuilderExt>(
builder: &mut AB,
idx: &mut usize,
expr: AB::Expr,
) {
tagged_assert_zero_integrity(builder, &STACK_ARITH_TAGS, idx, expr);
}