use miden_core::field::PrimeCharacteristicRing;
use miden_crypto::stark::air::LiftedAirBuilder;
use crate::{
MainTraceRow,
constraints::{
ext_field::QuadFeltExpr,
op_flags::OpFlags,
tagging::{
TagGroup, TaggingAirBuilderExt, ids::TAG_STACK_CRYPTO_BASE, tagged_assert_zero,
tagged_assert_zero_integrity,
},
},
trace::decoder::USER_OP_HELPERS_OFFSET,
};
#[allow(dead_code)]
pub const NUM_CONSTRAINTS: usize = 46;
const STACK_CRYPTO_BASE_ID: usize = TAG_STACK_CRYPTO_BASE;
const STACK_CRYPTO_NAMES: [&str; NUM_CONSTRAINTS] = [
"stack.crypto.cryptostream",
"stack.crypto.cryptostream",
"stack.crypto.cryptostream",
"stack.crypto.cryptostream",
"stack.crypto.cryptostream",
"stack.crypto.cryptostream",
"stack.crypto.cryptostream",
"stack.crypto.cryptostream",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerbase",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
"stack.crypto.hornerext",
];
const STACK_CRYPTO_TAGS: TagGroup = TagGroup {
base: STACK_CRYPTO_BASE_ID,
names: &STACK_CRYPTO_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;
enforce_cryptostream_constraints(builder, local, next, op_flags, &mut idx);
enforce_hornerbase_constraints(builder, local, next, op_flags, &mut idx);
enforce_hornerext_constraints(builder, local, next, op_flags, &mut idx);
}
fn enforce_cryptostream_constraints<AB>(
builder: &mut AB,
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
op_flags: &OpFlags<AB::Expr>,
idx: &mut usize,
) where
AB: LiftedAirBuilder,
{
let eight: AB::Expr = AB::Expr::from_u16(8);
let gate = op_flags.cryptostream();
assert_zero(
builder,
idx,
gate.clone() * (next.stack[8].clone().into() - local.stack[8].clone().into()),
);
assert_zero(
builder,
idx,
gate.clone() * (next.stack[9].clone().into() - local.stack[9].clone().into()),
);
assert_zero(
builder,
idx,
gate.clone() * (next.stack[10].clone().into() - local.stack[10].clone().into()),
);
assert_zero(
builder,
idx,
gate.clone() * (next.stack[11].clone().into() - local.stack[11].clone().into()),
);
assert_zero(
builder,
idx,
gate.clone()
* (next.stack[12].clone().into() - (local.stack[12].clone().into() + eight.clone())),
);
assert_zero(
builder,
idx,
gate.clone() * (next.stack[13].clone().into() - (local.stack[13].clone().into() + eight)),
);
assert_zero(
builder,
idx,
gate.clone() * (next.stack[14].clone().into() - local.stack[14].clone().into()),
);
assert_zero(
builder,
idx,
gate * (next.stack[15].clone().into() - local.stack[15].clone().into()),
);
}
fn enforce_hornerbase_constraints<AB>(
builder: &mut AB,
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
op_flags: &OpFlags<AB::Expr>,
idx: &mut usize,
) where
AB: LiftedAirBuilder,
{
let gate = op_flags.hornerbase();
for i in 0..14 {
assert_zero(
builder,
idx,
gate.clone() * (next.stack[i].clone().into() - local.stack[i].clone().into()),
);
}
let base = USER_OP_HELPERS_OFFSET;
let a0: AB::Expr = local.decoder[base].clone().into();
let a1: AB::Expr = local.decoder[base + 1].clone().into();
let tmp1_0: AB::Expr = local.decoder[base + 2].clone().into();
let tmp1_1: AB::Expr = local.decoder[base + 3].clone().into();
let tmp0_0: AB::Expr = local.decoder[base + 4].clone().into();
let tmp0_1: AB::Expr = local.decoder[base + 5].clone().into();
let acc0: AB::Expr = local.stack[14].clone().into();
let acc1: AB::Expr = local.stack[15].clone().into();
let acc0_next: AB::Expr = next.stack[14].clone().into();
let acc1_next: AB::Expr = next.stack[15].clone().into();
let c: [AB::Expr; 8] = core::array::from_fn(|i| local.stack[i].clone().into());
let alpha: QuadFeltExpr<AB::Expr> = QuadFeltExpr::new(&a0, &a1);
let alpha2 = alpha.clone().square();
let alpha3 = alpha2.clone() * alpha.clone();
let acc: QuadFeltExpr<AB::Expr> = QuadFeltExpr::new(&acc0, &acc1);
let acc_alpha2: QuadFeltExpr<AB::Expr> = acc * alpha2.clone();
let tmp0: QuadFeltExpr<AB::Expr> = QuadFeltExpr::new(&tmp0_0, &tmp0_1);
let tmp0_alpha3: QuadFeltExpr<AB::Expr> = tmp0.clone() * alpha3.clone();
let tmp1: QuadFeltExpr<AB::Expr> = QuadFeltExpr::new(&tmp1_0, &tmp1_1);
let tmp0_expected: QuadFeltExpr<AB::Expr> =
acc_alpha2 + alpha.clone() * c[0].clone() + c[1].clone();
let [tmp0_exp_0, tmp0_exp_1] = tmp0_expected.into_parts();
let tmp1_expected: QuadFeltExpr<AB::Expr> =
tmp0_alpha3 + alpha2.clone() * c[2].clone() + alpha.clone() * c[3].clone() + c[4].clone();
let [tmp1_exp_0, tmp1_exp_1] = tmp1_expected.into_parts();
let acc_expected: QuadFeltExpr<AB::Expr> =
tmp1 * alpha3 + alpha2.clone() * c[5].clone() + alpha.clone() * c[6].clone() + c[7].clone();
let [acc_exp_0, acc_exp_1] = acc_expected.into_parts();
assert_zero_integrity(builder, idx, gate.clone() * (tmp0_0 - tmp0_exp_0));
assert_zero_integrity(builder, idx, gate.clone() * (tmp0_1 - tmp0_exp_1));
assert_zero_integrity(builder, idx, gate.clone() * (tmp1_0 - tmp1_exp_0));
assert_zero_integrity(builder, idx, gate.clone() * (tmp1_1 - tmp1_exp_1));
assert_zero(builder, idx, gate.clone() * (acc0_next - acc_exp_0));
assert_zero(builder, idx, gate * (acc1_next - acc_exp_1));
}
fn enforce_hornerext_constraints<AB>(
builder: &mut AB,
local: &MainTraceRow<AB::Var>,
next: &MainTraceRow<AB::Var>,
op_flags: &OpFlags<AB::Expr>,
idx: &mut usize,
) where
AB: LiftedAirBuilder,
{
let gate = op_flags.hornerext();
for i in 0..14 {
assert_zero(
builder,
idx,
gate.clone() * (next.stack[i].clone().into() - local.stack[i].clone().into()),
);
}
let base = USER_OP_HELPERS_OFFSET;
let a0: AB::Expr = local.decoder[base].clone().into();
let a1: AB::Expr = local.decoder[base + 1].clone().into();
let tmp0: AB::Expr = local.decoder[base + 4].clone().into();
let tmp1: AB::Expr = local.decoder[base + 5].clone().into();
let acc0: AB::Expr = local.stack[14].clone().into();
let acc1: AB::Expr = local.stack[15].clone().into();
let acc0_next: AB::Expr = next.stack[14].clone().into();
let acc1_next: AB::Expr = next.stack[15].clone().into();
let s: [AB::Expr; 8] = core::array::from_fn(|i| local.stack[i].clone().into());
let alpha: QuadFeltExpr<AB::Expr> = QuadFeltExpr::new(&a0, &a1);
let alpha2 = alpha.clone().square();
let acc: QuadFeltExpr<AB::Expr> = QuadFeltExpr::new(&acc0, &acc1);
let acc_alpha2: QuadFeltExpr<AB::Expr> = acc * alpha2.clone();
let tmp: QuadFeltExpr<AB::Expr> = QuadFeltExpr::new(&tmp0, &tmp1);
let tmp_alpha2: QuadFeltExpr<AB::Expr> = tmp * alpha2;
let c0 = QuadFeltExpr::new(&s[0], &s[1]);
let c1 = QuadFeltExpr::new(&s[2], &s[3]);
let c2 = QuadFeltExpr::new(&s[4], &s[5]);
let c3 = QuadFeltExpr::new(&s[6], &s[7]);
let tmp_expected: QuadFeltExpr<AB::Expr> = acc_alpha2 + alpha.clone() * c0 + c1;
let [tmp_exp_0, tmp_exp_1] = tmp_expected.into_parts();
let acc_expected: QuadFeltExpr<AB::Expr> = tmp_alpha2 + alpha * c2 + c3;
let [acc_exp_0, acc_exp_1] = acc_expected.into_parts();
assert_zero_integrity(builder, idx, gate.clone() * (tmp0 - tmp_exp_0));
assert_zero_integrity(builder, idx, gate.clone() * (tmp1 - tmp_exp_1));
assert_zero(builder, idx, gate.clone() * (acc0_next - acc_exp_0));
assert_zero(builder, idx, gate * (acc1_next - acc_exp_1));
}
fn assert_zero<AB: TaggingAirBuilderExt>(builder: &mut AB, idx: &mut usize, expr: AB::Expr) {
tagged_assert_zero(builder, &STACK_CRYPTO_TAGS, idx, expr);
}
fn assert_zero_integrity<AB: TaggingAirBuilderExt>(
builder: &mut AB,
idx: &mut usize,
expr: AB::Expr,
) {
tagged_assert_zero_integrity(builder, &STACK_CRYPTO_TAGS, idx, expr);
}