use crate::fs::FiatShamir;
use lens::rspcs::field::quadratic_at;
use nebu::Fp3;
fn fold(v: &mut Vec<Fp3>, alpha: Fp3) {
let half = v.len() / 2;
for i in 0..half {
let x = v[2 * i];
v[i] = x + alpha * (v[2 * i + 1] - x);
}
v.truncate(half);
}
pub(crate) fn prove(
t: &mut impl FiatShamir,
mut a: Vec<Fp3>,
mut b: Vec<Fp3>,
extra: &mut [Vec<Fp3>],
) -> (Vec<Fp3>, Vec<Fp3>) {
let n = a.len().trailing_zeros() as usize;
let mut msgs = Vec::with_capacity(2 * n);
let mut point = Vec::with_capacity(n);
for _ in 0..n {
let (mut h0, mut h2) = (Fp3::ZERO, Fp3::ZERO);
for (ap, bp) in a.as_chunks::<2>().0.iter().zip(b.as_chunks::<2>().0.iter()) {
h0 += ap[0] * bp[0];
h2 += (ap[1] + ap[1] - ap[0]) * (bp[1] + bp[1] - bp[0]);
}
t.absorb_fp3(h0);
t.absorb_fp3(h2);
msgs.push(h0);
msgs.push(h2);
let alpha = t.squeeze_fp3();
fold(&mut a, alpha);
fold(&mut b, alpha);
for e in extra.iter_mut() {
fold(e, alpha);
}
point.push(alpha);
}
(msgs, point)
}
pub(crate) fn verify(
t: &mut impl FiatShamir,
sigma: Fp3,
msgs: &[Fp3],
n: usize,
) -> Option<(Vec<Fp3>, Fp3)> {
if msgs.len() != 2 * n {
return None;
}
let mut claim = sigma;
let mut point = Vec::with_capacity(n);
for p in msgs.as_chunks::<2>().0 {
t.absorb_fp3(p[0]);
t.absorb_fp3(p[1]);
let alpha = t.squeeze_fp3();
claim = quadratic_at(p[0], claim - p[0], p[1], alpha);
point.push(alpha);
}
Some((point, claim))
}