use nebu::{Fp3, Goldilocks};
use crate::air::num::Num;
use super::air::{Out, PUB_FIRST_ROW, PUB_INIT_TAG, PUB_MDS, PUB_OUT};
use super::layout::*;
use super::slots::{fingerprint, modes};
use crate::air::Vals;
pub(crate) fn ext<T: Num>(c: &[T]) -> T {
let t = T::from_fp3(Fp3::new(
Goldilocks::ZERO,
Goldilocks::ONE,
Goldilocks::ZERO,
));
c[0] + t * c[1] + t * t * c[2]
}
pub(crate) fn constrain<T: Num>(v: &Vals<'_, T>, ch: &[T], out: &mut Out<'_, T>) {
let (alpha, beta) = (ch[0], ch[1]);
let l = &v.local[..W1];
let h2 = &v.local[W1..];
let n2 = &v.next[W1..];
let p = v.publics;
let md = modes(l, p[PUB_INIT_TAG], p[PUB_MDS], p[PUB_OUT]);
let mut delta = T::ZERO;
for s in 0..SLOTS {
let h = ext(&h2[H0 + 3 * s..H0 + 3 * s + 3]);
let enc = fingerprint(l, md.tag[s], s, beta);
out.push(h * (alpha - enc) - T::ONE);
delta += (md.read[s] - md.write[s] * l[slot(s, M)]) * h;
}
let sum = ext(&h2[SUM..SUM + 3]);
let next = ext(&n2[SUM..SUM + 3]);
out.push(next - sum - delta);
out.push(p[PUB_FIRST_ROW] * sum);
}