use core::fmt::{Debug, Display};
use std::ops::Mul;
use serde::{Deserialize, Serialize};
use slop_air::{PairCol, VirtualPairCol};
use slop_algebra::{AbstractField, Field};
use slop_multilinear::MleEval;
use crate::air::InteractionScope;
#[derive(Clone)]
pub struct Interaction<F: Field> {
pub values: Vec<VirtualPairCol<F>>,
pub multiplicity: VirtualPairCol<F>,
pub kind: InteractionKind,
pub scope: InteractionScope,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum InteractionKind {
Memory = 1,
Program = 2,
Byte = 5,
State = 7,
Syscall = 8,
Global = 9,
ShaExtend = 10,
ShaCompress = 11,
Keccak = 12,
GlobalAccumulation = 13,
MemoryGlobalInitControl = 14,
MemoryGlobalFinalizeControl = 15,
InstructionFetch = 16,
InstructionDecode = 17,
PageProt = 18,
PageProtAccess = 19,
PageProtGlobalInitControl = 20,
PageProtGlobalFinalizeControl = 21,
}
impl InteractionKind {
#[must_use]
pub fn all_kinds() -> Vec<InteractionKind> {
vec![
InteractionKind::Memory,
InteractionKind::Program,
InteractionKind::Byte,
InteractionKind::State,
InteractionKind::Syscall,
InteractionKind::Global,
InteractionKind::ShaExtend,
InteractionKind::ShaCompress,
InteractionKind::Keccak,
InteractionKind::GlobalAccumulation,
InteractionKind::MemoryGlobalInitControl,
InteractionKind::MemoryGlobalFinalizeControl,
InteractionKind::InstructionFetch,
InteractionKind::InstructionDecode,
InteractionKind::PageProtAccess,
InteractionKind::PageProtGlobalInitControl,
InteractionKind::PageProtGlobalFinalizeControl,
InteractionKind::PageProt,
]
}
#[must_use]
pub fn num_values(&self) -> usize {
match self {
InteractionKind::Memory => 9,
#[cfg(feature = "mprotect")]
InteractionKind::Syscall => 10,
#[cfg(not(feature = "mprotect"))]
InteractionKind::Syscall => 9,
InteractionKind::Program => 16,
InteractionKind::Byte => 4,
InteractionKind::Global => 11,
InteractionKind::ShaCompress => 25,
InteractionKind::Keccak => 106,
InteractionKind::GlobalAccumulation => 15,
InteractionKind::InstructionFetch => 22,
InteractionKind::InstructionDecode => 19,
InteractionKind::ShaExtend
| InteractionKind::PageProt
| InteractionKind::PageProtAccess => 6,
InteractionKind::State
| InteractionKind::PageProtGlobalInitControl
| InteractionKind::PageProtGlobalFinalizeControl
| InteractionKind::MemoryGlobalInitControl
| InteractionKind::MemoryGlobalFinalizeControl => 5,
}
}
#[must_use]
pub fn appears_in_eval_public_values(&self) -> bool {
matches!(
self,
InteractionKind::Byte
| InteractionKind::State
| InteractionKind::MemoryGlobalFinalizeControl
| InteractionKind::MemoryGlobalInitControl
| InteractionKind::PageProtGlobalFinalizeControl
| InteractionKind::PageProtGlobalInitControl
| InteractionKind::GlobalAccumulation
)
}
}
impl<F: Field> Interaction<F> {
pub const fn new(
values: Vec<VirtualPairCol<F>>,
multiplicity: VirtualPairCol<F>,
kind: InteractionKind,
scope: InteractionScope,
) -> Self {
Self { values, multiplicity, kind, scope }
}
pub const fn argument_index(&self) -> usize {
self.kind as usize
}
pub fn eval<Expr, Var>(
&self,
preprocessed: Option<&MleEval<Var>>,
main: &MleEval<Var>,
alpha: Expr,
betas: &[Expr],
) -> (Expr, Expr)
where
F: Into<Expr>,
Expr: AbstractField + Mul<F, Output = Expr>,
Var: Into<Expr> + Copy,
{
let mut multiplicity_eval = self.multiplicity.constant.into();
for (column, weight) in self.multiplicity.column_weights.iter() {
let weight: Expr = (*weight).into();
match column {
PairCol::Preprocessed(i) => {
multiplicity_eval += preprocessed.as_ref().unwrap()[*i].into() * weight;
}
PairCol::Main(i) => multiplicity_eval += main[*i].into() * weight,
}
}
let mut betas = betas.iter().cloned();
let mut fingerprint_eval =
alpha + betas.next().unwrap() * Expr::from_canonical_usize(self.argument_index());
for (element, beta) in self.values.iter().zip(betas) {
let evaluation = if let Some(preprocessed) = preprocessed {
element.apply::<Expr, Var>(preprocessed, main)
} else {
element.apply::<Expr, Var>(&[], main)
};
fingerprint_eval += evaluation * beta;
}
(multiplicity_eval, fingerprint_eval)
}
}
impl<F: Field> Debug for Interaction<F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Interaction")
.field("kind", &self.kind)
.field("scope", &self.scope)
.finish_non_exhaustive()
}
}
impl Display for InteractionKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
InteractionKind::Memory => write!(f, "Memory"),
InteractionKind::Program => write!(f, "Program"),
InteractionKind::Byte => write!(f, "Byte"),
InteractionKind::State => write!(f, "State"),
InteractionKind::Syscall => write!(f, "Syscall"),
InteractionKind::Global => write!(f, "Global"),
InteractionKind::ShaExtend => write!(f, "ShaExtend"),
InteractionKind::ShaCompress => write!(f, "ShaCompress"),
InteractionKind::Keccak => write!(f, "Keccak"),
InteractionKind::GlobalAccumulation => write!(f, "GlobalAccumulation"),
InteractionKind::MemoryGlobalInitControl => write!(f, "MemoryGlobalInitControl"),
InteractionKind::MemoryGlobalFinalizeControl => {
write!(f, "MemoryGlobalFinalizeControl")
}
InteractionKind::InstructionFetch => write!(f, "InstructionFetch"),
InteractionKind::InstructionDecode => write!(f, "InstructionDecode"),
InteractionKind::PageProt => write!(f, "PageProt"),
InteractionKind::PageProtAccess => write!(f, "PageProtAccess"),
InteractionKind::PageProtGlobalInitControl => write!(f, "PageProtGlobalInitControl"),
InteractionKind::PageProtGlobalFinalizeControl => {
write!(f, "PageProtGlobalFinalizeControl")
}
}
}
}