use lens::rspcs::whir::LeafLayout;
use nebu::{Fp3, Goldilocks};
use super::circuit::trace::Pre;
use super::acc::{ClaimRef, InstV};
use super::ops::{Arith, Ops};
use super::perm::tag;
use super::sponge::{ProverTranscript, Sponge};
use super::state::{AccV, ClaimV};
use super::whir;
use super::word::{Arity, Digest, Group, Word};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Decider {
pub key: [Fp3; 2],
pub whir: whir::Proof,
}
pub struct KeyWords {
pub group: Group,
pub root: Digest,
}
impl KeyWords {
pub fn commit(layout: LeafLayout, n: usize, pre: &Pre, arity: Arity) -> (Self, bool) {
const WORD: usize = 64;
let rows = 1usize << n;
let ext = pre
.cols
.iter()
.flatten()
.any(|v| v.c1 != Goldilocks::ZERO || v.c2 != Goldilocks::ZERO);
let words = [0, 1].map(|h| {
let mut t = vec![Fp3::ZERO; WORD * rows];
for c in 0..WORD {
if let Some(col) = pre.cols.get(WORD * h + c) {
t[c * rows..(c + 1) * rows].copy_from_slice(col);
}
}
if ext {
Word::member_ext_streamed(layout, &t)
} else {
Word::member_base_streamed(layout, &t.iter().map(|v| v.c0).collect::<Vec<_>>())
}
});
let group = Group::new_cached(words.into(), arity);
let root = group.root();
(Self { group, root }, ext)
}
}
fn absorb<O: Ops>(o: &mut O, t: &mut Sponge<O>, acc: &AccV<O::V>, pv: &ClaimV<O::V>) {
t.absorb_all(o, &acc.root);
t.absorb_all_ext(o, &acc.rho);
t.absorb_ext(o, acc.v0);
for &(z, y) in &acc.ood {
t.absorb_ext(o, z);
t.absorb_ext(o, y);
}
for &(x, y) in &acc.spot {
t.absorb(o, x);
t.absorb_ext(o, y);
}
t.absorb_all_ext(o, &pv.point);
t.absorb_ext(o, pv.value);
}
fn inputs<V: Copy>(
acc: &AccV<V>,
key_root: [V; 4],
key_ext: bool,
z: &[V],
v: [V; 2],
) -> Vec<InstV<V>> {
let mut out = vec![acc.instance()];
for (root, val) in [key_root; 2].into_iter().zip(v) {
out.push(InstV {
root,
ext: key_ext,
claims: vec![ClaimRef::Multi(z.to_vec(), val)],
});
}
out
}
pub fn prove(
cfg: &whir::Config,
acc_word: &Word,
acc: &AccV<Fp3>,
pv: &ClaimV<Fp3>,
key: &KeyWords,
n: usize,
) -> Result<Decider, String> {
let lap = super::ivc::timer_pub(" decide ");
let mut t = ProverTranscript::new(tag::DECIDE);
absorb(&mut t.o, &mut t.sp, acc, pv);
let zg = &pv.point[..n + 6];
let v = [key.group.words[0].table(), key.group.words[1].table()]
.map(|tb| lens::rspcs::field::ml_eval_ext(&tb, zg));
t.absorb_ext(v[0]);
t.absorb_ext(v[1]);
lap("key claim");
let vars = acc.rho.len();
let up = |x: Fp3| lens::rspcs::field::pow_point(x, vars);
let mut acc_claims = vec![(acc.rho.clone(), acc.v0)];
acc_claims.extend(acc.ood.iter().map(|&(z, y)| (up(z), y)));
acc_claims.extend(acc.spot.iter().map(|&(x, y)| (up(x), y)));
let claims = vec![
acc_claims,
vec![(zg.to_vec(), v[0])],
vec![(zg.to_vec(), v[1])],
];
lap("claims");
let whir = whir::prove(
cfg,
&mut t,
&[acc_word as &dyn whir::Tree, &key.group],
&claims,
)?;
lap("opening");
Ok(Decider { key: v, whir })
}
#[allow(clippy::too_many_arguments)]
pub fn verify<O: Ops>(
o: &mut O,
cfg: &whir::Config,
acc: &AccV<O::V>,
pv: &ClaimV<O::V>,
key_root: Digest,
key_ext: bool,
n: usize,
pf: &Decider,
) {
let mut t = Sponge::new(o, tag::DECIDE);
absorb(o, &mut t, acc, pv);
let v = [
t.absorb_free_ext(o, pf.key[0]),
t.absorb_free_ext(o, pf.key[1]),
];
let g6 = pv.point[n + 6];
let line = o.lerp(g6, v[0], v[1]);
o.assert_eq(line, pv.value, "decider: the key claim");
let root = key_root.map(|x| o.constant(Fp3::from_base(x)));
let ins = inputs(acc, root, key_ext, &pv.point[..n + 6], v);
whir::verify(o, cfg, &mut t, &ins, &pf.whir);
}
pub fn dummy(cfg: &whir::Config) -> Decider {
Decider {
key: [Fp3::ZERO; 2],
whir: whir::dummy(cfg),
}
}
pub fn check_shape(cfg: &whir::Config, pf: &Decider) -> Result<(), String> {
whir::check_shape(cfg, 3, &pf.whir)
}